| /* |
| * dav_svn.h: types, functions, macros for the DAV/SVN Apache module |
| * |
| * ==================================================================== |
| * 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. |
| * ==================================================================== |
| */ |
| |
| #ifndef DAV_SVN_H |
| #define DAV_SVN_H |
| |
| #include <apr_tables.h> |
| #include <apr_xml.h> |
| |
| #include <httpd.h> |
| #include <http_log.h> |
| #include <mod_dav.h> |
| |
| #include "svn_error.h" |
| #include "svn_fs.h" |
| #include "svn_repos.h" |
| #include "svn_path.h" |
| #include "svn_xml.h" |
| #include "private/svn_dav_protocol.h" |
| #include "private/svn_skel.h" |
| #include "mod_authz_svn.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif /* __cplusplus */ |
| |
| |
| |
| /* what the one VCC is called */ |
| #define DAV_SVN__DEFAULT_VCC_NAME "default" |
| |
| /* a pool-key for the shared dav_svn_root used by autoversioning */ |
| #define DAV_SVN__AUTOVERSIONING_ACTIVITY "svn-autoversioning-activity" |
| |
| /* Option values for SVNAllowBulkUpdates. Note that |
| it's important that CONF_BULKUPD_DEFAULT is 0 to make |
| merge_dir_config in mod_dav_svn do the right thing. */ |
| typedef enum dav_svn__bulk_upd_conf { |
| CONF_BULKUPD_DEFAULT, |
| CONF_BULKUPD_ON, |
| CONF_BULKUPD_OFF, |
| CONF_BULKUPD_PREFER |
| } dav_svn__bulk_upd_conf; |
| |
| /* dav_svn_repos |
| * |
| * Record information about the repository that a resource belongs to. |
| * This structure will be shared between multiple resources so that we |
| * can optimized our FS access. |
| * |
| * Note that we do not refcount this structure. Presumably, we will need |
| * it throughout the life of the request. Therefore, we can just leave it |
| * for the request pool to cleanup/close. |
| * |
| * Also, note that it is possible that two resources may have distinct |
| * dav_svn_repos structures, yet refer to the same repository. This is |
| * allowed by the SVN FS interface. |
| * |
| * ### should we attempt to merge them when we detect this situation in |
| * ### places like is_same_resource, is_parent_resource, or copy/move? |
| * ### I say yes: the FS will certainly have an easier time if there is |
| * ### only a single FS open; otherwise, it will have to work a bit harder |
| * ### to keep the things in sync. |
| */ |
| typedef struct dav_svn_repos { |
| apr_pool_t *pool; /* request_rec -> pool */ |
| |
| /* Remember the root URL path of this repository (just a path; no |
| scheme, host, or port). |
| |
| Example: the URI is "http://host/repos/file", this will be "/repos". |
| |
| This always starts with "/", and if there are any components |
| beyond that, then it does not end with "/". |
| */ |
| const char *root_path; |
| |
| /* Remember an absolute URL for constructing other URLs. In the above |
| example, this would be "http://host" (note: no trailing slash) |
| */ |
| const char *base_url; |
| |
| /* Remember the special URI component for this repository */ |
| const char *special_uri; |
| |
| /* This records the filesystem path to the SVN FS */ |
| const char *fs_path; |
| |
| /* The name of this repository */ |
| const char *repo_name; |
| |
| /* The repository filesystem basename */ |
| const char *repo_basename; |
| |
| /* The URI of the XSL transform for directory indexes */ |
| const char *xslt_uri; |
| |
| /* Whether autoversioning is active for this repository. */ |
| svn_boolean_t autoversioning; |
| |
| /* Whether bulk updates are allowed for this repository. */ |
| dav_svn__bulk_upd_conf bulk_updates; |
| |
| /* Whether HTTP protocol version 2 is allowed to be used. */ |
| svn_boolean_t v2_protocol; |
| |
| /* the open repository */ |
| svn_repos_t *repos; |
| |
| /* a cached copy of REPOS->fs above. */ |
| svn_fs_t *fs; |
| |
| /* the user operating against this repository */ |
| const char *username; |
| |
| /* is the client a Subversion client? */ |
| svn_boolean_t is_svn_client; |
| |
| /* The client's capabilities. Maps SVN_RA_CAPABILITY_* keys to |
| "yes" or "no" values. If a capability is not yet discovered, it |
| is absent from the table. The table itself is allocated in this |
| structure's 'pool' field, and the keys and values must have at |
| least that lifetime. Most likely the keys and values are |
| constants anyway (and sufficiently well-informed internal code |
| may therefore compare against those constants' addresses). If |
| 'is_svn_client' is false, then 'capabilities' should be empty. */ |
| apr_hash_t *client_capabilities; |
| |
| /* The path to the activities db */ |
| const char *activities_db; |
| |
| /* Cached yongest revision of the repository. SVN_INVALID_REVNUM if |
| youngest revision is not fetched yet. */ |
| svn_revnum_t youngest_rev; |
| } dav_svn_repos; |
| |
| |
| /* |
| ** dav_svn_private_restype: identifiers for our different private resources |
| ** |
| ** There are some resources within mod_dav_svn that are "privately defined". |
| ** This isn't so much to prevent other people from knowing what they are, |
| ** but merely that mod_dav doesn't have a standard name for them. |
| */ |
| enum dav_svn_private_restype { |
| DAV_SVN_RESTYPE_UNSET, |
| |
| DAV_SVN_RESTYPE_ROOT_COLLECTION, /* .../!svn/ */ |
| DAV_SVN_RESTYPE_VER_COLLECTION, /* .../!svn/ver/ */ |
| DAV_SVN_RESTYPE_HIS_COLLECTION, /* .../!svn/his/ */ |
| DAV_SVN_RESTYPE_WRK_COLLECTION, /* .../!svn/wrk/ */ |
| DAV_SVN_RESTYPE_ACT_COLLECTION, /* .../!svn/act/ */ |
| DAV_SVN_RESTYPE_VCC_COLLECTION, /* .../!svn/vcc/ */ |
| DAV_SVN_RESTYPE_BC_COLLECTION, /* .../!svn/bc/ */ |
| DAV_SVN_RESTYPE_BLN_COLLECTION, /* .../!svn/bln/ */ |
| DAV_SVN_RESTYPE_WBL_COLLECTION, /* .../!svn/wbl/ */ |
| DAV_SVN_RESTYPE_VCC, /* .../!svn/vcc/NAME */ |
| DAV_SVN_RESTYPE_PARENTPATH_COLLECTION,/* see SVNParentPath directive */ |
| |
| /* new types in HTTP protocol v2: */ |
| DAV_SVN_RESTYPE_ME, /* .../!svn/me */ |
| DAV_SVN_RESTYPE_REV_COLLECTION, /* .../!svn/rev/ */ |
| DAV_SVN_RESTYPE_REVROOT_COLLECTION, /* .../!svn/rvr/ */ |
| DAV_SVN_RESTYPE_TXN_COLLECTION, /* .../!svn/txn/ */ |
| DAV_SVN_RESTYPE_TXNROOT_COLLECTION /* .../!svn/txr/ */ |
| }; |
| |
| |
| /* store info about a root in a repository */ |
| typedef struct dav_svn_root { |
| /* If a root within the FS has been opened, the value is stored here. |
| Otherwise, this field is NULL. */ |
| svn_fs_root_t *root; |
| |
| /* If the root has been opened, and it was opened for a specific revision, |
| then it is contained in REV. If the root is unopened or corresponds to |
| a transaction, then REV will be SVN_INVALID_REVNUM. */ |
| svn_revnum_t rev; |
| |
| /* If this resource is an activity or part of an activity, this specifies |
| the ID of that activity. It may not (yet) correspond to a transaction |
| in the FS. |
| |
| WORKING and ACTIVITY resources use this field. |
| */ |
| const char *activity_id; |
| |
| /* If the root is part of a transaction, this contains the FS's transaction |
| name. It may be NULL if this root corresponds to a specific revision. |
| It may also be NULL if we have not opened the root yet. |
| |
| WORKING and ACTIVITY resources use this field, as well as PRIVATE |
| resources that directly represent either a txn or txn-root. |
| */ |
| const char *txn_name; |
| |
| /* The optional vtxn name supplied by an HTTPv2 client and |
| used in subsequent requests. This may be NULL if the client |
| is not using a vtxn name. |
| |
| PRIVATE resources that directly represent either a txn or |
| txn-root use this field. |
| */ |
| const char *vtxn_name; |
| |
| /* If the root is part of a transaction, this contains the FS's transaction |
| handle. It may be NULL if this root corresponds to a specific revision. |
| It may also be NULL if we have not opened the transaction yet. |
| |
| WORKING resources use this field. |
| */ |
| svn_fs_txn_t *txn; |
| |
| } dav_svn_root; |
| |
| |
| /* internal structure to hold information about this resource */ |
| struct dav_resource_private { |
| /* Path from the SVN repository root to this resource. This value has |
| a leading slash. It will never have a trailing slash, even if the |
| resource represents a collection. |
| |
| For example: URI is http://host/repos/file -- path will be "/file". |
| |
| NOTE: this path is from the URI and does NOT necessarily correspond |
| to a path within the FS repository. |
| */ |
| svn_stringbuf_t *uri_path; |
| |
| /* The FS repository path to this resource, with a leading "/". Note |
| that this is "/" the root. This value will be NULL for resources |
| that have no corresponding resource within the repository (such as |
| the PRIVATE resources, Baselines, or Working Baselines). */ |
| const char *repos_path; |
| |
| /* the FS repository this resource is associated with */ |
| dav_svn_repos *repos; |
| |
| /* what FS root this resource occurs within */ |
| dav_svn_root root; |
| |
| /* for PRIVATE resources: the private resource type */ |
| enum dav_svn_private_restype restype; |
| |
| /* The request which created this resource. We need this to |
| generate subrequests. */ |
| request_rec *r; |
| |
| /* ### hack to deal with the Content-Type header on a PUT */ |
| int is_svndiff; |
| |
| /* ### record the base for computing a delta during a GET */ |
| const char *delta_base; |
| |
| /* SVNDIFF version we can transmit to the client. */ |
| int svndiff_version; |
| |
| /* the value of any SVN_DAV_OPTIONS_HEADER that came in the request */ |
| const char *svn_client_options; |
| |
| /* the revnum value from a possible SVN_DAV_VERSION_NAME_HEADER */ |
| svn_revnum_t version_name; |
| |
| /* Hex MD5 digests for base text and resultant fulltext. |
| Either or both of these may be null, in which case ignored. */ |
| const char *base_checksum; |
| const char *result_checksum; |
| |
| /* was this resource auto-checked-out? */ |
| svn_boolean_t auto_checked_out; |
| |
| /* was this resource fetched using our public peg-/working-rev CGI |
| interface (ie: /path/to/item?p=PEGREV)? */ |
| svn_boolean_t pegged; |
| |
| /* Cache any revprop change error */ |
| svn_error_t *revprop_error; |
| |
| /* was keyword substitution requested using our public CGI interface |
| (ie: /path/to/item?kw=1)? */ |
| svn_boolean_t keyword_subst; |
| |
| /* whether this resource parameters are fixed and won't change |
| between requests. */ |
| svn_boolean_t idempotent; |
| |
| /* resource is accessed by 'public' uri (not under "!svn") */ |
| svn_boolean_t is_public_uri; |
| }; |
| |
| |
| /* Every provider needs to define an opaque locktoken type. */ |
| struct dav_locktoken |
| { |
| /* This is identical to the 'token' field of an svn_lock_t. */ |
| const char *uuid_str; |
| }; |
| |
| |
| /* for the repository referred to by this request, where is the SVN FS? */ |
| const char *dav_svn__get_fs_path(request_rec *r); |
| const char *dav_svn__get_fs_parent_path(request_rec *r); |
| |
| /* for the repository referred to by this request, is autoversioning active? */ |
| svn_boolean_t dav_svn__get_autoversioning_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, are bulk updates allowed? */ |
| dav_svn__bulk_upd_conf dav_svn__get_bulk_updates_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, are subrequests active? */ |
| svn_boolean_t dav_svn__get_pathauthz_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, is txdelta caching active? */ |
| svn_boolean_t dav_svn__get_txdelta_cache_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, is fulltext caching active? */ |
| svn_boolean_t dav_svn__get_fulltext_cache_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, is revprop caching active? */ |
| svn_boolean_t dav_svn__get_revprop_cache_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, is node prop caching active? */ |
| svn_boolean_t |
| dav_svn__get_nodeprop_cache_flag(request_rec *r); |
| |
| /* has block read mode been enabled for the repository referred to by this |
| * request? */ |
| svn_boolean_t dav_svn__get_block_read_flag(request_rec *r); |
| |
| /* for the repository referred to by this request, are subrequests bypassed? |
| * A function pointer if yes, NULL if not. |
| */ |
| authz_svn__subreq_bypass_func_t dav_svn__get_pathauthz_bypass(request_rec *r); |
| |
| /* for the repository referred to by this request, is a GET of |
| SVNParentPath allowed? */ |
| svn_boolean_t dav_svn__get_list_parentpath_flag(request_rec *r); |
| |
| /* For the repository referred to by this request, should HTTPv2 |
| protocol support be advertised? Note that this also takes into |
| account the support level expected of based on the specified |
| master server version (if provided via SVNMasterVersion). */ |
| svn_boolean_t dav_svn__check_httpv2_support(request_rec *r); |
| |
| |
| |
| /* SPECIAL URI |
| |
| SVN needs to create many types of "pseudo resources" -- resources |
| that don't correspond to the users' files/directories in the |
| repository. Specifically, these are: |
| |
| - working resources |
| - activities |
| - version resources |
| - version history resources |
| |
| Each of these will be placed under a portion of the URL namespace |
| that defines the SVN repository. For example, let's say the user |
| has configured an SVN repository at http://host/svn/repos. The |
| special resources could be configured to live at .../!svn/ under |
| that repository. Thus, an activity might be located at |
| http://host/svn/repos/!svn/act/1234. |
| |
| The special URI is configurable on a per-server basis and defaults |
| to "!svn". |
| |
| NOTE: the special URI is RELATIVE to the "root" of the |
| repository. The root is generally available only to |
| dav_svn_get_resource(). This is okay, however, because we can cache |
| the root_dir when the resource structure is built. |
| */ |
| |
| /* Return the repo-root-relative URI of the special namespace to be used for |
| * this resource. |
| * Comes from the <SVNSpecialURI> directive. */ |
| /* ### Is this assumed to be URI-encoded? */ |
| const char *dav_svn__get_special_uri(request_rec *r); |
| |
| /* Return a descriptive name for the repository. |
| * Comes from the <SVNReposName> directive. */ |
| const char *dav_svn__get_repo_name(request_rec *r); |
| |
| /* Return the server-relative URI of an XSL transform stylesheet. |
| Comes from the <SVNIndexXSLT> directive. */ |
| /* ### Is this assumed to be URI-encoded? */ |
| const char *dav_svn__get_xslt_uri(request_rec *r); |
| |
| /* Return the full URL of the master repository (for mirroring). |
| Comes from the <SVNMasterURI> directive. */ |
| /* ### Is this assumed to be URI-encoded? */ |
| const char *dav_svn__get_master_uri(request_rec *r); |
| |
| /* Return the version of the master server (used for mirroring) iff a |
| master URI is in place for this location; otherwise, return NULL. |
| Comes from the <SVNMasterVersion> directive. */ |
| svn_version_t *dav_svn__get_master_version(request_rec *r); |
| |
| /* Return the disk path to the activities db. |
| Comes from the <SVNActivitiesDB> directive. */ |
| const char *dav_svn__get_activities_db(request_rec *r); |
| |
| /* Return the server-relative URI of the repository root. |
| Comes from the <Location> directive. */ |
| /* ### Is this assumed to be URI-encoded? */ |
| const char *dav_svn__get_root_dir(request_rec *r); |
| |
| /* Return the data compression level to be used over the wire. */ |
| int dav_svn__get_compression_level(request_rec *r); |
| |
| /* Return the hook script environment parsed from the configuration. */ |
| const char *dav_svn__get_hooks_env(request_rec *r); |
| |
| /** For HTTP protocol v2, these are the new URIs and URI stubs |
| returned to the client in our OPTIONS response. They all depend |
| on the 'special uri', which is configurable in httpd.conf. **/ |
| |
| /* Where REPORT requests are sent (typically "!svn/me") */ |
| const char *dav_svn__get_me_resource_uri(request_rec *r); |
| |
| /* For accessing revision resources (typically "!svn/rev") */ |
| const char *dav_svn__get_rev_stub(request_rec *r); |
| |
| /* For accessing REV/PATH pairs (typically "!svn/bc") */ |
| const char *dav_svn__get_rev_root_stub(request_rec *r); |
| |
| /* For accessing transaction resources (typically "!svn/txn") */ |
| const char *dav_svn__get_txn_stub(request_rec *r); |
| |
| /* For accessing transaction properties (typically "!svn/txr") */ |
| const char *dav_svn__get_txn_root_stub(request_rec *r); |
| |
| /* For accessing transaction resources (typically "!svn/vtxn") */ |
| const char *dav_svn__get_vtxn_stub(request_rec *r); |
| |
| /* For accessing transaction properties (typically "!svn/vtxr") */ |
| const char *dav_svn__get_vtxn_root_stub(request_rec *r); |
| |
| |
| /*** Output helpers ***/ |
| |
| /* An opaque type which represents an output for a particular request. |
| |
| All writes should target a dav_svn__output object by either using |
| the dav_svn__brigade functions or by preparing a bucket brigade and |
| passing it to the output with dav_svn__output_pass_brigade(). |
| |
| IMPORTANT: Don't write to an ap_filter_t coming from mod_dav, and |
| use this wrapper and the corresponding private API instead. Using |
| the ap_filter_t can cause unbounded memory usage with self-removing |
| output filters (e.g., with the filters installed by mod_headers or |
| mod_deflate). |
| |
| See https://mail-archives.apache.org/mod_mbox/httpd-dev/201608.mbox/%3C20160822151917.GA22369%40redhat.com%3E |
| */ |
| typedef struct dav_svn__output dav_svn__output; |
| |
| /* Create the output wrapper for request R, allocated in POOL. */ |
| dav_svn__output * |
| dav_svn__output_create(request_rec *r, |
| apr_pool_t *pool); |
| |
| /* Get a bucket allocator to use for all bucket/brigade creations |
| when writing to OUTPUT. */ |
| apr_bucket_alloc_t * |
| dav_svn__output_get_bucket_alloc(dav_svn__output *output); |
| |
| /* Pass the bucket brigade BB down to the OUTPUT's filter stack. */ |
| svn_error_t * |
| dav_svn__output_pass_brigade(dav_svn__output *output, |
| apr_bucket_brigade *bb); |
| |
| |
| /*** activity.c ***/ |
| |
| /* Create a new transaction based on HEAD in REPOS, setting *PTXN_NAME |
| to the name of that transaction. REVPROPS is an optional hash of |
| const char * property names and const svn_string_t * values which |
| will be set as transactions properties on the transaction this |
| function creates. Use POOL for allocations. |
| |
| NOTE: This function will overwrite the svn:author property, if |
| any, found in REVPROPS. */ |
| dav_error * |
| dav_svn__create_txn(dav_svn_repos *repos, |
| const char **ptxn_name, |
| apr_hash_t *revprops, |
| apr_pool_t *pool); |
| |
| /* If it exists, abort the transaction named TXN_NAME from REPOS. Use |
| POOL for allocations. */ |
| dav_error * |
| dav_svn__abort_txn(const dav_svn_repos *repos, |
| const char *txn_name, |
| apr_pool_t *pool); |
| |
| /* Functions for looking up, storing, and deleting ACTIVITY->TXN mappings. */ |
| const char * |
| dav_svn__get_txn(const dav_svn_repos *repos, const char *activity_id); |
| |
| dav_error * |
| dav_svn__delete_activity(const dav_svn_repos *repos, const char *activity_id); |
| |
| dav_error * |
| dav_svn__store_activity(const dav_svn_repos *repos, |
| const char *activity_id, |
| const char *txn_name); |
| |
| |
| /* POST request handler. (Used by HTTP protocol v2 clients only.) */ |
| int dav_svn__method_post(request_rec *r); |
| |
| /* Request handler to GET Subversion internal status (FSFS cache). */ |
| int dav_svn__status(request_rec *r); |
| |
| /*** repos.c ***/ |
| |
| /* generate an ETag for RESOURCE and return it, allocated in POOL. */ |
| const char * |
| dav_svn__getetag(const dav_resource *resource, apr_pool_t *pool); |
| |
| /* |
| Construct a working resource for a given resource. |
| |
| The internal information (repository, URL parts, etc) for the new |
| resource comes from BASE, the activity to use is specified by |
| ACTIVITY_ID, and the name of the transaction is specified by |
| TXN_NAME. These will be assembled into a new dav_resource and |
| returned. |
| |
| If TWEAK_IN_PLACE is non-zero, then directly tweak BASE into a |
| working resource and return NULL. |
| */ |
| dav_resource * |
| dav_svn__create_working_resource(dav_resource *base, |
| const char *activity_id, |
| const char *txn_name, |
| int tweak_in_place); |
| /* |
| Convert a working RESOURCE back into a regular one, in-place. |
| |
| In particular: change the resource type to regular, removing the |
| 'working' flag, change the fs root from a txn-root to a rev-root, |
| and set the URL back into either a public URL or bc URL. |
| */ |
| dav_error * |
| dav_svn__working_to_regular_resource(dav_resource *resource); |
| |
| /* |
| Given a version-resource URI, construct a new version-resource in |
| POOL and return it in *VERSION_RES. |
| */ |
| dav_error * |
| dav_svn__create_version_resource(dav_resource **version_res, |
| const char *uri, |
| apr_pool_t *pool); |
| |
| extern const dav_hooks_repository dav_svn__hooks_repository; |
| |
| |
| /*** deadprops.c ***/ |
| extern const dav_hooks_propdb dav_svn__hooks_propdb; |
| |
| |
| /*** lock.c ***/ |
| extern const dav_hooks_locks dav_svn__hooks_locks; |
| |
| |
| /*** version.c ***/ |
| |
| /* For an autoversioning commit, a helper function which attaches an |
| auto-generated 'svn:log' property to a txn, as well as a property |
| that indicates the revision was made via autoversioning. */ |
| svn_error_t * |
| dav_svn__attach_auto_revprops(svn_fs_txn_t *txn, |
| const char *fs_path, |
| apr_pool_t *pool); |
| |
| |
| /* Hook function of types 'checkout' and 'checkin', as defined in |
| mod_dav.h's versioning provider hooks table (see dav_hooks_vsn). */ |
| dav_error * |
| dav_svn__checkout(dav_resource *resource, |
| int auto_checkout, |
| int is_unreserved, |
| int is_fork_ok, |
| int create_activity, |
| apr_array_header_t *activities, |
| dav_resource **working_resource); |
| |
| dav_error * |
| dav_svn__checkin(dav_resource *resource, |
| int keep_checked_out, |
| dav_resource **version_resource); |
| |
| |
| /* Helper for reading lock-tokens out of request bodies, by looking |
| for cached body in R->pool's userdata. |
| |
| Return a hash that maps (const char *) absolute fs paths to (const |
| char *) locktokens. Allocate the hash and all keys/vals in POOL. |
| PATH_PREFIX is the prefix we need to prepend to each relative |
| 'lock-path' in the xml in order to create an absolute fs-path. */ |
| dav_error * |
| dav_svn__build_lock_hash(apr_hash_t **locks, |
| request_rec *r, |
| const char *path_prefix, |
| apr_pool_t *pool); |
| |
| |
| /* Helper: push all of the lock-tokens (hash values) in LOCKS into |
| RESOURCE's already-open svn_fs_t. */ |
| dav_error * |
| dav_svn__push_locks(dav_resource *resource, |
| apr_hash_t *locks, |
| apr_pool_t *pool); |
| |
| |
| extern const dav_hooks_vsn dav_svn__hooks_vsn; |
| |
| |
| /*** liveprops.c ***/ |
| |
| extern const dav_liveprop_group dav_svn__liveprop_group; |
| |
| /* |
| LIVE PROPERTY HOOKS |
| |
| These are standard hooks defined by mod_dav. We implement them to expose |
| various live properties on the resources under our control. |
| |
| gather_propsets: appends URIs into the array; the property set URIs are |
| used to specify which sets of custom properties we |
| define/expose. |
| find_liveprop: given a namespace and name, return the hooks for the |
| provider who defines that property. |
| insert_all_liveprops: for a given resource, insert all of the live |
| properties defined on that resource. The properties |
| are inserted according to the WHAT parameter. |
| */ |
| void dav_svn__gather_propsets(apr_array_header_t *uris); |
| |
| int |
| dav_svn__find_liveprop(const dav_resource *resource, |
| const char *ns_uri, |
| const char *name, |
| const dav_hooks_liveprop **hooks); |
| |
| void |
| dav_svn__insert_all_liveprops(request_rec *r, |
| const dav_resource *resource, |
| dav_prop_insert what, |
| apr_text_header *phdr); |
| |
| |
| /*** merge.c ***/ |
| |
| /* Generate the HTTP response body for a successful MERGE. */ |
| /* ### more docco */ |
| dav_error * |
| dav_svn__merge_response(dav_svn__output *output, |
| const dav_svn_repos *repos, |
| svn_revnum_t new_rev, |
| const char *post_commit_err, |
| apr_xml_elem *prop_elem, |
| svn_boolean_t disable_merge_response, |
| apr_pool_t *pool); |
| |
| |
| /*** reports/ ***/ |
| |
| /* The list of Subversion's custom REPORTs. */ |
| /* ### should move these report names to a public header to share with |
| ### the client (and third parties). */ |
| static const dav_report_elem dav_svn__reports_list[] = { |
| { SVN_XML_NAMESPACE, "update-report" }, |
| { SVN_XML_NAMESPACE, "log-report" }, |
| { SVN_XML_NAMESPACE, "dated-rev-report" }, |
| { SVN_XML_NAMESPACE, "get-locations" }, |
| { SVN_XML_NAMESPACE, "get-location-segments" }, |
| { SVN_XML_NAMESPACE, "file-revs-report" }, |
| { SVN_XML_NAMESPACE, "get-locks-report" }, |
| { SVN_XML_NAMESPACE, "replay-report" }, |
| { SVN_XML_NAMESPACE, "get-deleted-rev-report" }, |
| { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_REPORT }, |
| { SVN_XML_NAMESPACE, SVN_DAV__INHERITED_PROPS_REPORT }, |
| { SVN_XML_NAMESPACE, "list-report" }, |
| { NULL, NULL }, |
| }; |
| |
| |
| /* The various report handlers, defined in reports/, and used by version.c. */ |
| dav_error * |
| dav_svn__update_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__log_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__dated_rev_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__get_locations_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__get_location_segments_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__file_revs_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__replay_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__get_mergeinfo_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__get_locks_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| |
| dav_error * |
| dav_svn__get_deleted_rev_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| |
| dav_error * |
| dav_svn__get_inherited_props_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| |
| dav_error * |
| dav_svn__list_report(const dav_resource *resource, |
| const apr_xml_doc *doc, |
| dav_svn__output *output); |
| |
| /*** posts/ ***/ |
| |
| /* The various POST handlers, defined in posts/, and used by repos.c. */ |
| dav_error * |
| dav_svn__post_create_txn(const dav_resource *resource, |
| svn_skel_t *request_skel, |
| dav_svn__output *output); |
| dav_error * |
| dav_svn__post_create_txn_with_props(const dav_resource *resource, |
| svn_skel_t *request_skel, |
| dav_svn__output *output); |
| |
| /*** authz.c ***/ |
| |
| /* A baton needed by dav_svn__authz_read_func(). */ |
| typedef struct dav_svn__authz_read_baton |
| { |
| /* The original request, needed to generate a subrequest. */ |
| request_rec *r; |
| |
| /* We need this to construct a URI based on a repository abs path. */ |
| const dav_svn_repos *repos; |
| |
| } dav_svn__authz_read_baton; |
| |
| |
| /* Return TRUE iff the current user (as determined by Apache's |
| authentication system) has permission to read PATH in REPOS at REV |
| (where an invalid REV means "HEAD"). This will invoke any authz |
| modules loaded into Apache unless this Subversion location has been |
| configured to bypass those in favor of a direct lookup in the |
| Subversion authz subsystem. Use POOL for any temporary allocation. |
| */ |
| svn_boolean_t |
| dav_svn__allow_read(request_rec *r, |
| const dav_svn_repos *repos, |
| const char *path, |
| svn_revnum_t rev, |
| apr_pool_t *pool); |
| |
| /* Return TRUE iff the current user (as determined by Apache's |
| authentication system) has permission to read RESOURCE in REV |
| (where an invalid REV means "HEAD"). This will invoke any authz |
| modules loaded into Apache unless this Subversion location has been |
| configured to bypass those in favor of a direct lookup in the |
| Subversion authz subsystem. Use POOL for any temporary allocation. |
| */ |
| svn_boolean_t |
| dav_svn__allow_read_resource(const dav_resource *resource, |
| svn_revnum_t rev, |
| apr_pool_t *pool); |
| |
| |
| /* Return TRUE iff the current user (as determined by Apache's |
| authentication system) has permission to read repository REPOS_NAME. |
| This will invoke any authz modules loaded into Apache unless this |
| Subversion location has been configured to bypass those in favor of a |
| direct lookup in the Subversion authz subsystem. Use POOL for any |
| temporary allocation. |
| IMPORTANT: R must be request for DAV_SVN_RESTYPE_PARENTPATH_COLLECTION |
| resource. |
| */ |
| svn_boolean_t |
| dav_svn__allow_list_repos(request_rec *r, |
| const char *repos_name, |
| apr_pool_t *pool); |
| |
| /* If authz is enabled in the specified BATON, return a read authorization |
| function. Otherwise, return NULL. */ |
| svn_repos_authz_func_t |
| dav_svn__authz_read_func(dav_svn__authz_read_baton *baton); |
| |
| |
| /*** util.c ***/ |
| |
| /* A wrapper around mod_dav's dav_new_error_tag, mod_dav_svn uses this |
| instead of the mod_dav function to enable special mod_dav_svn specific |
| processing. See dav_new_error_tag for parameter documentation. |
| Note that DESC may be null (it's hard to track this down from |
| dav_new_error_tag()'s documentation, but see the dav_error type, |
| which says that its desc field may be NULL). |
| |
| If ERROR_ID is 0, SVN_ERR_RA_DAV_REQUEST_FAILED will be used as a |
| default value for the error code. |
| |
| mod_dav is definitive documentation of the parameters, but a |
| guideline to the different error is: |
| |
| STATUS is the HTTP status returned to the client. |
| |
| ERROR_ID is an additional DAV-specific error such as a violation of |
| the DAV rules. mod_dav.h defines some values but callers can pass |
| others. |
| |
| APRERR is any underlying OS/system error. |
| */ |
| dav_error * |
| dav_svn__new_error_svn(apr_pool_t *pool, |
| int status, |
| int error_id, |
| apr_status_t aprerr, |
| const char *desc); |
| |
| |
| /* A wrapper around mod_dav's dav_new_error, mod_dav_svn uses this |
| instead of the mod_dav function to enable special mod_dav_svn specific |
| processing. See dav_svn__new_error_svn for additional details. |
| */ |
| dav_error * |
| dav_svn__new_error(apr_pool_t *pool, |
| int status, |
| int error_id, |
| apr_status_t aprerr, |
| const char *desc); |
| |
| |
| /* Convert an svn_error_t into a dav_error, pushing another error based on |
| MESSAGE if MESSAGE is not NULL. Use the provided HTTP status for the |
| DAV errors. Allocate new DAV errors from POOL. |
| |
| NOTE: this function destroys (cleanly, of course) SERR after it has |
| copied/converted its data to the new DAV error. |
| |
| NOTE: MESSAGE needs to hang around for the lifetime of the error since |
| the current implementation doesn't copy it! Lots of callers pass static |
| string constant. */ |
| dav_error * |
| dav_svn__convert_err(svn_error_t *serr, |
| int status, |
| const char *message, |
| apr_pool_t *pool); |
| |
| |
| /* Compare (PATH in ROOT) to (PATH in ROOT/PATH's created_rev). |
| |
| If these nodes are identical, then return the created_rev. |
| |
| If the nodes aren't identical, or if PATH simply doesn't exist in |
| the created_rev, then return the revision represented by ROOT. |
| |
| (This is a helper to functions that want to build version-urls and |
| use the CR if possible.) */ |
| svn_revnum_t |
| dav_svn__get_safe_cr(svn_fs_root_t *root, const char *path, apr_pool_t *pool); |
| |
| |
| /* Construct various kinds of URIs. |
| |
| REPOS is always required, as all URIs will be built to refer to elements |
| within that repository. WHAT specifies the type of URI to build. The |
| ADD_HREF flag determines whether the URI is to be wrapped inside of |
| <D:href>uri</D:href> elements (for inclusion in a response). |
| |
| Different pieces of information are required for the various URI types: |
| |
| ACT_COLLECTION: no additional params required |
| BASELINE: REVISION should be specified |
| BC: REVISION should be specified |
| PUBLIC: PATH should be specified with a leading slash |
| VERSION: REVISION and PATH should be specified |
| VCC: no additional params required |
| */ |
| enum dav_svn__build_what { |
| DAV_SVN__BUILD_URI_ACT_COLLECTION, /* the collection of activities */ |
| DAV_SVN__BUILD_URI_BASELINE, /* a Baseline */ |
| DAV_SVN__BUILD_URI_BC, /* a Baseline Collection */ |
| DAV_SVN__BUILD_URI_PUBLIC, /* the "public" VCR */ |
| DAV_SVN__BUILD_URI_VERSION, /* a Version Resource */ |
| DAV_SVN__BUILD_URI_VCC, /* a Version Controlled Configuration */ |
| DAV_SVN__BUILD_URI_REVROOT /* HTTPv2: Revision Root resource */ |
| }; |
| |
| const char * |
| dav_svn__build_uri(const dav_svn_repos *repos, |
| enum dav_svn__build_what what, |
| svn_revnum_t revision, |
| const char *path, |
| svn_boolean_t add_href, |
| apr_pool_t *pool); |
| |
| |
| /* Simple parsing of a URI. This is used for URIs which appear within a |
| request body. It enables us to verify and break out the necessary pieces |
| to figure out what is being referred to. |
| |
| ### this is horribly duplicative with the parsing functions in repos.c |
| ### for now, this implements only a minor subset of the full range of |
| ### URIs which we may need to parse. it also ignores any scheme, host, |
| ### and port in the URI and simply assumes it refers to the same server. |
| */ |
| typedef struct dav_svn__uri_info { |
| svn_revnum_t rev; |
| const char *repos_path; |
| const char *activity_id; |
| } dav_svn__uri_info; |
| |
| svn_error_t * |
| dav_svn__simple_parse_uri(dav_svn__uri_info *info, |
| const dav_resource *relative, |
| const char *uri, |
| apr_pool_t *pool); |
| |
| /* Test the request R to determine if we should return the list of |
| * repositories at the parent path. Only true if SVNListParentPath directive |
| * is 'on' and the request is for our configured root path. */ |
| svn_boolean_t |
| dav_svn__is_parentpath_list(request_rec *r); |
| |
| |
| int dav_svn__find_ns(const apr_array_header_t *namespaces, const char *uri); |
| |
| |
| |
| /*** Brigade I/O wrappers ***/ |
| |
| /* Write LEN bytes from DATA to OUTPUT using BB. */ |
| svn_error_t *dav_svn__brigade_write(apr_bucket_brigade *bb, |
| dav_svn__output *output, |
| const char *buf, |
| apr_size_t len); |
| |
| /* Write NULL-terminated string STR to OUTPUT using BB. */ |
| svn_error_t *dav_svn__brigade_puts(apr_bucket_brigade *bb, |
| dav_svn__output *output, |
| const char *str); |
| |
| |
| /* Write data to OUTPUT using BB, using FMT as the output format string. */ |
| svn_error_t *dav_svn__brigade_printf(apr_bucket_brigade *bb, |
| dav_svn__output *output, |
| const char *fmt, |
| ...) |
| __attribute__((format(printf, 3, 4))); |
| |
| /* Write an unspecified number of strings to OUTPUT using BB. */ |
| svn_error_t *dav_svn__brigade_putstrs(apr_bucket_brigade *bb, |
| dav_svn__output *output, |
| ...) SVN_NEEDS_SENTINEL_NULL; |
| |
| |
| |
| |
| /* Test PATH for canonicalness (defined as "what won't make the |
| svn_path_* functions immediately explode"), returning an |
| HTTP_BAD_REQUEST error tag if the test fails. */ |
| dav_error *dav_svn__test_canonical(const char *path, apr_pool_t *pool); |
| |
| |
| /* Convert @a serr into a dav_error. If @a new_msg is non-NULL, use |
| @a new_msg in the returned error, and write the original |
| @a serr->message to httpd's log. Destroy the passed-in @a serr, |
| similarly to dav_svn__convert_err(). |
| |
| @a new_msg is usually a "sanitized" version of @a serr->message. |
| That is, if @a serr->message contains security-sensitive data, |
| @a new_msg does not. |
| |
| The purpose of sanitization is to prevent security-sensitive data |
| from being transmitted over the network to the client. The error |
| messages produced by various APIs (e.g., svn_fs, svn_repos) may |
| contain security-sensitive data such as the actual server file |
| system's path to the repository. We don't want to send that to the |
| client, but we do want to log the real error on the server side. |
| */ |
| dav_error * |
| dav_svn__sanitize_error(svn_error_t *serr, |
| const char *new_msg, |
| int http_status, |
| request_rec *r); |
| |
| |
| /* Return a writable generic stream that will encode its output to base64 |
| and send it to OUTPUT using BB. Allocate the stream in POOL. */ |
| svn_stream_t * |
| dav_svn__make_base64_output_stream(apr_bucket_brigade *bb, |
| dav_svn__output *output, |
| apr_pool_t *pool); |
| |
| /* In INFO->r->subprocess_env set "SVN-ACTION" to LINE, "SVN-REPOS" to |
| * INFO->repos->fs_path, and "SVN-REPOS-NAME" to INFO->repos->repo_basename. */ |
| void |
| dav_svn__operational_log(struct dav_resource_private *info, const char *line); |
| |
| /* Flush BB if it's okay and useful to do so, but treat PREFERRED_ERR |
| * as a more important error to return (if it is non-NULL). |
| * |
| * This is intended to be used at the end of response processing, |
| * probably called as a direct return generator, like so: |
| * |
| * return dav_svn__final_flush_or_error(r, bb, output, derr, resource->pool); |
| * |
| * SOME BACKGROUND INFO: |
| * |
| * We don't flush the brigade unless there's something in it to |
| * flush; that way, we have the opportunity to package a dav_error up |
| * for transmission back to the client. |
| * |
| * To understand this, see mod_dav.c:dav_method_report(): as long as |
| * it doesn't think we've sent anything to the client, it'll send |
| * the real error, which is what we'd prefer. This situation is |
| * described in httpd-2.2.6/modules/dav/main/mod_dav.c, line 4066, |
| * in the comment in dav_method_report() that says: |
| * |
| * If an error occurred during the report delivery, there's |
| * basically nothing we can do but abort the connection and |
| * log an error. This is one of the limitations of HTTP; it |
| * needs to "know" the entire status of the response before |
| * generating it, which is just impossible in these streamy |
| * response situations. |
| * |
| * In other words, flushing the brigade causes r->sent_bodyct (see |
| * dav_method_report()) to become non-zero, even if we hadn't tried to |
| * send any data to the brigade yet. So we don't flush unless data |
| * was actually sent. |
| */ |
| dav_error * |
| dav_svn__final_flush_or_error(request_rec *r, apr_bucket_brigade *bb, |
| dav_svn__output *output, |
| dav_error *preferred_err, |
| apr_pool_t *pool); |
| |
| /* Log a DAV error response. |
| * |
| * NOTE: Copied from mod_dav's dav_log_err which is not public. |
| */ |
| void dav_svn__log_err(request_rec *r, |
| dav_error *err, |
| int level); |
| |
| /* Send a "standardized" DAV error response based on the ERR's |
| * namespace and tag. |
| * |
| * NOTE: This was copied pretty much directory from mod_dav's |
| * dav_error_response_tag() function which is, sadly, not public. |
| */ |
| int dav_svn__error_response_tag(request_rec *r, dav_error *err); |
| |
| |
| /* Set *SKEL to a parsed skel read from the body of request R, and |
| * allocated in POOL. |
| */ |
| int dav_svn__parse_request_skel(svn_skel_t **skel, request_rec *r, |
| apr_pool_t *pool); |
| |
| /* Set *YOUNGEST_P to the number of the youngest revision in REPOS. |
| * |
| * Youngest revision will be cached in REPOS->YOUNGEST_REV to avoid |
| * fetching the youngest revision multiple times during processing |
| * the request. |
| * |
| * Uses SCRATCH_POOL for temporary allocations. |
| */ |
| svn_error_t * |
| dav_svn__get_youngest_rev(svn_revnum_t *youngest_p, |
| dav_svn_repos *repos, |
| apr_pool_t *scratch_pool); |
| |
| /* Return the liveprop-encoded form of AUTHOR, allocated in RESULT_POOL. |
| * If IS_SVN_CLIENT is set, assume that the data will be sent to a SVN |
| * client. This mainly sanitizes AUTHOR strings with control chars in |
| * them without converting them to escape sequences etc. |
| * |
| * Use SCRATCH_POOL for temporary allocations. |
| */ |
| const char * |
| dav_svn__fuzzy_escape_author(const char *author, |
| svn_boolean_t is_svn_client, |
| apr_pool_t *result_pool, |
| apr_pool_t *scratch_pool); |
| |
| /*** mirror.c ***/ |
| |
| /* Perform the fixup hook for the R request. */ |
| int dav_svn__proxy_request_fixup(request_rec *r); |
| |
| /* An Apache input filter which rewrites the locations in headers and |
| request body. It reads from filter F using BB data, MODE mode, BLOCK |
| blocking strategy, and READBYTES. */ |
| apr_status_t dav_svn__location_in_filter(ap_filter_t *f, |
| apr_bucket_brigade *bb, |
| ap_input_mode_t mode, |
| apr_read_type_e block, |
| apr_off_t readbytes); |
| |
| /* An Apache output filter F which rewrites the response headers for |
| * location headers. It will modify the stream in BB. */ |
| apr_status_t dav_svn__location_header_filter(ap_filter_t *f, |
| apr_bucket_brigade *bb); |
| |
| /* An Apache output filter F which rewrites the response body for |
| * location headers. It will modify the stream in BB. */ |
| apr_status_t dav_svn__location_body_filter(ap_filter_t *f, |
| apr_bucket_brigade *bb); |
| |
| |
| #ifdef __cplusplus |
| } |
| #endif /* __cplusplus */ |
| |
| #endif /* DAV_SVN_H */ |