1 /*
2  * dav_svn.h: types, functions, macros for the DAV/SVN Apache module
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23 
24 #ifndef DAV_SVN_H
25 #define DAV_SVN_H
26 
27 #include <apr_tables.h>
28 #include <apr_xml.h>
29 
30 #include <httpd.h>
31 #include <http_log.h>
32 #include <mod_dav.h>
33 
34 #include "svn_error.h"
35 #include "svn_fs.h"
36 #include "svn_repos.h"
37 #include "svn_path.h"
38 #include "svn_xml.h"
39 #include "private/svn_dav_protocol.h"
40 #include "private/svn_skel.h"
41 #include "mod_authz_svn.h"
42 
43 #ifdef __cplusplus
44 extern "C" {
45 #endif /* __cplusplus */
46 
47 
48 
49 /* what the one VCC is called */
50 #define DAV_SVN__DEFAULT_VCC_NAME        "default"
51 
52 /* a pool-key for the shared dav_svn_root used by autoversioning  */
53 #define DAV_SVN__AUTOVERSIONING_ACTIVITY "svn-autoversioning-activity"
54 
55 /* Option values for SVNAllowBulkUpdates.  Note that
56    it's important that CONF_BULKUPD_DEFAULT is 0 to make
57    merge_dir_config in mod_dav_svn do the right thing. */
58 typedef enum dav_svn__bulk_upd_conf {
59     CONF_BULKUPD_DEFAULT,
60     CONF_BULKUPD_ON,
61     CONF_BULKUPD_OFF,
62     CONF_BULKUPD_PREFER
63 } dav_svn__bulk_upd_conf;
64 
65 /* dav_svn_repos
66  *
67  * Record information about the repository that a resource belongs to.
68  * This structure will be shared between multiple resources so that we
69  * can optimized our FS access.
70  *
71  * Note that we do not refcount this structure. Presumably, we will need
72  * it throughout the life of the request. Therefore, we can just leave it
73  * for the request pool to cleanup/close.
74  *
75  * Also, note that it is possible that two resources may have distinct
76  * dav_svn_repos structures, yet refer to the same repository. This is
77  * allowed by the SVN FS interface.
78  *
79  * ### should we attempt to merge them when we detect this situation in
80  * ### places like is_same_resource, is_parent_resource, or copy/move?
81  * ### I say yes: the FS will certainly have an easier time if there is
82  * ### only a single FS open; otherwise, it will have to work a bit harder
83  * ### to keep the things in sync.
84  */
85 typedef struct dav_svn_repos {
86   apr_pool_t *pool;     /* request_rec -> pool */
87 
88   /* Remember the root URL path of this repository (just a path; no
89      scheme, host, or port).
90 
91      Example: the URI is "http://host/repos/file", this will be "/repos".
92 
93      This always starts with "/", and if there are any components
94      beyond that, then it does not end with "/".
95   */
96   const char *root_path;
97 
98   /* Remember an absolute URL for constructing other URLs. In the above
99      example, this would be "http://host" (note: no trailing slash)
100   */
101   const char *base_url;
102 
103   /* Remember the special URI component for this repository */
104   const char *special_uri;
105 
106   /* This records the filesystem path to the SVN FS */
107   const char *fs_path;
108 
109   /* The name of this repository */
110   const char *repo_name;
111 
112   /* The repository filesystem basename */
113   const char *repo_basename;
114 
115   /* The URI of the XSL transform for directory indexes */
116   const char *xslt_uri;
117 
118   /* Whether autoversioning is active for this repository. */
119   svn_boolean_t autoversioning;
120 
121   /* Whether bulk updates are allowed for this repository. */
122   dav_svn__bulk_upd_conf bulk_updates;
123 
124   /* Whether HTTP protocol version 2 is allowed to be used. */
125   svn_boolean_t v2_protocol;
126 
127   /* the open repository */
128   svn_repos_t *repos;
129 
130   /* a cached copy of REPOS->fs above. */
131   svn_fs_t *fs;
132 
133   /* the user operating against this repository */
134   const char *username;
135 
136   /* is the client a Subversion client? */
137   svn_boolean_t is_svn_client;
138 
139   /* The client's capabilities.  Maps SVN_RA_CAPABILITY_* keys to
140      "yes" or "no" values.  If a capability is not yet discovered, it
141      is absent from the table.  The table itself is allocated in this
142      structure's 'pool' field, and the keys and values must have at
143      least that lifetime.  Most likely the keys and values are
144      constants anyway (and sufficiently well-informed internal code
145      may therefore compare against those constants' addresses).  If
146      'is_svn_client' is false, then 'capabilities' should be empty. */
147   apr_hash_t *client_capabilities;
148 
149   /* The path to the activities db */
150   const char *activities_db;
151 
152   /* Cached yongest revision of the repository. SVN_INVALID_REVNUM if
153      youngest revision is not fetched yet. */
154   svn_revnum_t youngest_rev;
155 } dav_svn_repos;
156 
157 
158 /*
159 ** dav_svn_private_restype: identifiers for our different private resources
160 **
161 ** There are some resources within mod_dav_svn that are "privately defined".
162 ** This isn't so much to prevent other people from knowing what they are,
163 ** but merely that mod_dav doesn't have a standard name for them.
164 */
165 enum dav_svn_private_restype {
166   DAV_SVN_RESTYPE_UNSET,
167 
168   DAV_SVN_RESTYPE_ROOT_COLLECTION,      /* .../!svn/     */
169   DAV_SVN_RESTYPE_VER_COLLECTION,       /* .../!svn/ver/ */
170   DAV_SVN_RESTYPE_HIS_COLLECTION,       /* .../!svn/his/ */
171   DAV_SVN_RESTYPE_WRK_COLLECTION,       /* .../!svn/wrk/ */
172   DAV_SVN_RESTYPE_ACT_COLLECTION,       /* .../!svn/act/ */
173   DAV_SVN_RESTYPE_VCC_COLLECTION,       /* .../!svn/vcc/ */
174   DAV_SVN_RESTYPE_BC_COLLECTION,        /* .../!svn/bc/  */
175   DAV_SVN_RESTYPE_BLN_COLLECTION,       /* .../!svn/bln/ */
176   DAV_SVN_RESTYPE_WBL_COLLECTION,       /* .../!svn/wbl/ */
177   DAV_SVN_RESTYPE_VCC,                  /* .../!svn/vcc/NAME */
178   DAV_SVN_RESTYPE_PARENTPATH_COLLECTION,/* see SVNParentPath directive */
179 
180   /* new types in HTTP protocol v2: */
181   DAV_SVN_RESTYPE_ME,                   /* .../!svn/me   */
182   DAV_SVN_RESTYPE_REV_COLLECTION,       /* .../!svn/rev/ */
183   DAV_SVN_RESTYPE_REVROOT_COLLECTION,   /* .../!svn/rvr/ */
184   DAV_SVN_RESTYPE_TXN_COLLECTION,       /* .../!svn/txn/ */
185   DAV_SVN_RESTYPE_TXNROOT_COLLECTION    /* .../!svn/txr/ */
186 };
187 
188 
189 /* store info about a root in a repository */
190 typedef struct dav_svn_root {
191   /* If a root within the FS has been opened, the value is stored here.
192      Otherwise, this field is NULL. */
193   svn_fs_root_t *root;
194 
195   /* If the root has been opened, and it was opened for a specific revision,
196      then it is contained in REV. If the root is unopened or corresponds to
197      a transaction, then REV will be SVN_INVALID_REVNUM. */
198   svn_revnum_t rev;
199 
200   /* If this resource is an activity or part of an activity, this specifies
201      the ID of that activity. It may not (yet) correspond to a transaction
202      in the FS.
203 
204      WORKING and ACTIVITY resources use this field.
205   */
206   const char *activity_id;
207 
208   /* If the root is part of a transaction, this contains the FS's tranaction
209      name. It may be NULL if this root corresponds to a specific revision.
210      It may also be NULL if we have not opened the root yet.
211 
212      WORKING and ACTIVITY resources use this field, as well as PRIVATE
213      resources that directly represent either a txn or txn-root.
214   */
215   const char *txn_name;
216 
217   /* The optional vtxn name supplied by an HTTPv2 client and
218      used in subsequent requests.  This may be NULL if the client
219      is not using a vtxn name.
220 
221      PRIVATE resources that directly represent either a txn or
222      txn-root use this field.
223   */
224   const char *vtxn_name;
225 
226   /* If the root is part of a transaction, this contains the FS's transaction
227      handle. It may be NULL if this root corresponds to a specific revision.
228      It may also be NULL if we have not opened the transaction yet.
229 
230      WORKING resources use this field.
231   */
232   svn_fs_txn_t *txn;
233 
234 } dav_svn_root;
235 
236 
237 /* internal structure to hold information about this resource */
238 struct dav_resource_private {
239   /* Path from the SVN repository root to this resource. This value has
240      a leading slash. It will never have a trailing slash, even if the
241      resource represents a collection.
242 
243      For example: URI is http://host/repos/file -- path will be "/file".
244 
245      NOTE: this path is from the URI and does NOT necessarily correspond
246            to a path within the FS repository.
247   */
248   svn_stringbuf_t *uri_path;
249 
250   /* The FS repository path to this resource, with a leading "/". Note
251      that this is "/" the root. This value will be NULL for resources
252      that have no corresponding resource within the repository (such as
253      the PRIVATE resources, Baselines, or Working Baselines). */
254   const char *repos_path;
255 
256   /* the FS repository this resource is associated with */
257   dav_svn_repos *repos;
258 
259   /* what FS root this resource occurs within */
260   dav_svn_root root;
261 
262   /* for PRIVATE resources: the private resource type */
263   enum dav_svn_private_restype restype;
264 
265   /* The request which created this resource.  We need this to
266      generate subrequests. */
267   request_rec *r;
268 
269   /* ### hack to deal with the Content-Type header on a PUT */
270   int is_svndiff;
271 
272   /* ### record the base for computing a delta during a GET */
273   const char *delta_base;
274 
275   /* SVNDIFF version we can transmit to the client.  */
276   int svndiff_version;
277 
278   /* the value of any SVN_DAV_OPTIONS_HEADER that came in the request */
279   const char *svn_client_options;
280 
281   /* the revnum value from a possible SVN_DAV_VERSION_NAME_HEADER */
282   svn_revnum_t version_name;
283 
284   /* Hex MD5 digests for base text and resultant fulltext.
285      Either or both of these may be null, in which case ignored. */
286   const char *base_checksum;
287   const char *result_checksum;
288 
289   /* was this resource auto-checked-out? */
290   svn_boolean_t auto_checked_out;
291 
292   /* was this resource fetched using our public peg-/working-rev CGI
293      interface (ie: /path/to/item?p=PEGREV)? */
294   svn_boolean_t pegged;
295 
296   /* Cache any revprop change error */
297   svn_error_t *revprop_error;
298 
299   /* was keyword substitution requested using our public CGI interface
300      (ie: /path/to/item?kw=1)? */
301   svn_boolean_t keyword_subst;
302 
303   /* whether this resource parameters are fixed and won't change
304      between requests. */
305   svn_boolean_t idempotent;
306 
307   /* resource is accessed by 'public' uri (not under "!svn") */
308   svn_boolean_t is_public_uri;
309 };
310 
311 
312 /* Every provider needs to define an opaque locktoken type. */
313 struct dav_locktoken
314 {
315   /* This is identical to the 'token' field of an svn_lock_t. */
316   const char *uuid_str;
317 };
318 
319 
320 /* for the repository referred to by this request, where is the SVN FS? */
321 const char *dav_svn__get_fs_path(request_rec *r);
322 const char *dav_svn__get_fs_parent_path(request_rec *r);
323 
324 /* for the repository referred to by this request, is autoversioning active? */
325 svn_boolean_t dav_svn__get_autoversioning_flag(request_rec *r);
326 
327 /* for the repository referred to by this request, are bulk updates allowed? */
328 dav_svn__bulk_upd_conf dav_svn__get_bulk_updates_flag(request_rec *r);
329 
330 /* for the repository referred to by this request, are subrequests active? */
331 svn_boolean_t dav_svn__get_pathauthz_flag(request_rec *r);
332 
333 /* for the repository referred to by this request, is txdelta caching active? */
334 svn_boolean_t dav_svn__get_txdelta_cache_flag(request_rec *r);
335 
336 /* for the repository referred to by this request, is fulltext caching active? */
337 svn_boolean_t dav_svn__get_fulltext_cache_flag(request_rec *r);
338 
339 /* for the repository referred to by this request, is revprop caching active? */
340 svn_boolean_t dav_svn__get_revprop_cache_flag(request_rec *r);
341 
342 /* for the repository referred to by this request, is node prop caching active? */
343 svn_boolean_t
344 dav_svn__get_nodeprop_cache_flag(request_rec *r);
345 
346 /* has block read mode been enabled for the repository referred to by this
347  * request? */
348 svn_boolean_t dav_svn__get_block_read_flag(request_rec *r);
349 
350 /* for the repository referred to by this request, are subrequests bypassed?
351  * A function pointer if yes, NULL if not.
352  */
353 authz_svn__subreq_bypass_func_t dav_svn__get_pathauthz_bypass(request_rec *r);
354 
355 /* for the repository referred to by this request, is a GET of
356    SVNParentPath allowed? */
357 svn_boolean_t dav_svn__get_list_parentpath_flag(request_rec *r);
358 
359 /* For the repository referred to by this request, should HTTPv2
360    protocol support be advertised?  Note that this also takes into
361    account the support level expected of based on the specified
362    master server version (if provided via SVNMasterVersion).  */
363 svn_boolean_t dav_svn__check_httpv2_support(request_rec *r);
364 
365 
366 
367 /* SPECIAL URI
368 
369    SVN needs to create many types of "pseudo resources" -- resources
370    that don't correspond to the users' files/directories in the
371    repository. Specifically, these are:
372 
373    - working resources
374    - activities
375    - version resources
376    - version history resources
377 
378    Each of these will be placed under a portion of the URL namespace
379    that defines the SVN repository. For example, let's say the user
380    has configured an SVN repository at http://host/svn/repos. The
381    special resources could be configured to live at .../!svn/ under
382    that repository. Thus, an activity might be located at
383    http://host/svn/repos/!svn/act/1234.
384 
385    The special URI is configurable on a per-server basis and defaults
386    to "!svn".
387 
388    NOTE: the special URI is RELATIVE to the "root" of the
389    repository. The root is generally available only to
390    dav_svn_get_resource(). This is okay, however, because we can cache
391    the root_dir when the resource structure is built.
392 */
393 
394 /* Return the repo-root-relative URI of the special namespace to be used for
395  * this resource.
396  * Comes from the <SVNSpecialURI> directive. */
397 /* ### Is this assumed to be URI-encoded? */
398 const char *dav_svn__get_special_uri(request_rec *r);
399 
400 /* Return a descriptive name for the repository.
401  * Comes from the <SVNReposName> directive. */
402 const char *dav_svn__get_repo_name(request_rec *r);
403 
404 /* Return the server-relative URI of an XSL transform stylesheet.
405    Comes from the <SVNIndexXSLT> directive. */
406 /* ### Is this assumed to be URI-encoded? */
407 const char *dav_svn__get_xslt_uri(request_rec *r);
408 
409 /* Return the full URL of the master repository (for mirroring).
410    Comes from the <SVNMasterURI> directive. */
411 /* ### Is this assumed to be URI-encoded? */
412 const char *dav_svn__get_master_uri(request_rec *r);
413 
414 /* Return the version of the master server (used for mirroring) iff a
415    master URI is in place for this location; otherwise, return NULL.
416    Comes from the <SVNMasterVersion> directive. */
417 svn_version_t *dav_svn__get_master_version(request_rec *r);
418 
419 /* Return the disk path to the activities db.
420    Comes from the <SVNActivitiesDB> directive. */
421 const char *dav_svn__get_activities_db(request_rec *r);
422 
423 /* Return the server-relative URI of the repository root.
424    Comes from the <Location> directive. */
425 /* ### Is this assumed to be URI-encoded? */
426 const char *dav_svn__get_root_dir(request_rec *r);
427 
428 /* Return the data compression level to be used over the wire. */
429 int dav_svn__get_compression_level(request_rec *r);
430 
431 /* Return the hook script environment parsed from the configuration. */
432 const char *dav_svn__get_hooks_env(request_rec *r);
433 
434 /** For HTTP protocol v2, these are the new URIs and URI stubs
435     returned to the client in our OPTIONS response.  They all depend
436     on the 'special uri', which is configurable in httpd.conf.  **/
437 
438 /* Where REPORT requests are sent (typically "!svn/me") */
439 const char *dav_svn__get_me_resource_uri(request_rec *r);
440 
441 /* For accessing revision resources (typically "!svn/rev") */
442 const char *dav_svn__get_rev_stub(request_rec *r);
443 
444 /* For accessing REV/PATH pairs (typically "!svn/bc") */
445 const char *dav_svn__get_rev_root_stub(request_rec *r);
446 
447 /* For accessing transaction resources (typically "!svn/txn") */
448 const char *dav_svn__get_txn_stub(request_rec *r);
449 
450 /* For accessing transaction properties (typically "!svn/txr") */
451 const char *dav_svn__get_txn_root_stub(request_rec *r);
452 
453 /* For accessing transaction resources (typically "!svn/vtxn") */
454 const char *dav_svn__get_vtxn_stub(request_rec *r);
455 
456 /* For accessing transaction properties (typically "!svn/vtxr") */
457 const char *dav_svn__get_vtxn_root_stub(request_rec *r);
458 
459 
460 /*** Output helpers ***/
461 
462 /* An opaque type which represents an output for a particular request.
463 
464    All writes should target a dav_svn__output object by either using
465    the dav_svn__brigade functions or by preparing a bucket brigade and
466    passing it to the output with dav_svn__output_pass_brigade().
467 
468    IMPORTANT:  Don't write to an ap_filter_t coming from mod_dav, and
469    use this wrapper and the corresponding private API instead.  Using
470    the ap_filter_t can cause unbounded memory usage with self-removing
471    output filters (e.g., with the filters installed by mod_headers or
472    mod_deflate).
473 
474    See https://mail-archives.apache.org/mod_mbox/httpd-dev/201608.mbox/%3C20160822151917.GA22369%40redhat.com%3E
475 */
476 typedef struct dav_svn__output dav_svn__output;
477 
478 /* Create the output wrapper for request R, allocated in POOL. */
479 dav_svn__output *
480 dav_svn__output_create(request_rec *r,
481                        apr_pool_t *pool);
482 
483 /* Get a bucket allocator to use for all bucket/brigade creations
484    when writing to OUTPUT. */
485 apr_bucket_alloc_t *
486 dav_svn__output_get_bucket_alloc(dav_svn__output *output);
487 
488 /* Pass the bucket brigade BB down to the OUTPUT's filter stack. */
489 svn_error_t *
490 dav_svn__output_pass_brigade(dav_svn__output *output,
491                              apr_bucket_brigade *bb);
492 
493 
494 /*** activity.c ***/
495 
496 /* Create a new transaction based on HEAD in REPOS, setting *PTXN_NAME
497    to the name of that transaction.  REVPROPS is an optional hash of
498    const char * property names and const svn_string_t * values which
499    will be set as transactions properties on the transaction this
500    function creates.  Use POOL for allocations.
501 
502    NOTE:  This function will overwrite the svn:author property, if
503    any, found in REVPROPS.  */
504 dav_error *
505 dav_svn__create_txn(dav_svn_repos *repos,
506                     const char **ptxn_name,
507                     apr_hash_t *revprops,
508                     apr_pool_t *pool);
509 
510 /* If it exists, abort the transaction named TXN_NAME from REPOS.  Use
511    POOL for allocations. */
512 dav_error *
513 dav_svn__abort_txn(const dav_svn_repos *repos,
514                    const char *txn_name,
515                    apr_pool_t *pool);
516 
517 /* Functions for looking up, storing, and deleting ACTIVITY->TXN mappings.  */
518 const char *
519 dav_svn__get_txn(const dav_svn_repos *repos, const char *activity_id);
520 
521 dav_error *
522 dav_svn__delete_activity(const dav_svn_repos *repos, const char *activity_id);
523 
524 dav_error *
525 dav_svn__store_activity(const dav_svn_repos *repos,
526                         const char *activity_id,
527                         const char *txn_name);
528 
529 
530 /* POST request handler.  (Used by HTTP protocol v2 clients only.)  */
531 int dav_svn__method_post(request_rec *r);
532 
533 /* Request handler to GET Subversion internal status (FSFS cache). */
534 int dav_svn__status(request_rec *r);
535 
536 /*** repos.c ***/
537 
538 /* generate an ETag for RESOURCE and return it, allocated in POOL. */
539 const char *
540 dav_svn__getetag(const dav_resource *resource, apr_pool_t *pool);
541 
542 /*
543   Construct a working resource for a given resource.
544 
545   The internal information (repository, URL parts, etc) for the new
546   resource comes from BASE, the activity to use is specified by
547   ACTIVITY_ID, and the name of the transaction is specified by
548   TXN_NAME. These will be assembled into a new dav_resource and
549   returned.
550 
551   If TWEAK_IN_PLACE is non-zero, then directly tweak BASE into a
552   working resource and return NULL.
553 */
554 dav_resource *
555 dav_svn__create_working_resource(dav_resource *base,
556                                  const char *activity_id,
557                                  const char *txn_name,
558                                  int tweak_in_place);
559 /*
560    Convert a working RESOURCE back into a regular one, in-place.
561 
562    In particular: change the resource type to regular, removing the
563    'working' flag, change the fs root from a txn-root to a rev-root,
564    and set the URL back into either a public URL or bc URL.
565 */
566 dav_error *
567 dav_svn__working_to_regular_resource(dav_resource *resource);
568 
569 /*
570    Given a version-resource URI, construct a new version-resource in
571    POOL and return it in  *VERSION_RES.
572 */
573 dav_error *
574 dav_svn__create_version_resource(dav_resource **version_res,
575                                  const char *uri,
576                                  apr_pool_t *pool);
577 
578 extern const dav_hooks_repository dav_svn__hooks_repository;
579 
580 
581 /*** deadprops.c ***/
582 extern const dav_hooks_propdb dav_svn__hooks_propdb;
583 
584 
585 /*** lock.c ***/
586 extern const dav_hooks_locks dav_svn__hooks_locks;
587 
588 
589 /*** version.c ***/
590 
591 /* For an autoversioning commit, a helper function which attaches an
592    auto-generated 'svn:log' property to a txn, as well as a property
593    that indicates the revision was made via autoversioning. */
594 svn_error_t *
595 dav_svn__attach_auto_revprops(svn_fs_txn_t *txn,
596                               const char *fs_path,
597                               apr_pool_t *pool);
598 
599 
600 /* Hook function of types 'checkout' and 'checkin', as defined in
601    mod_dav.h's versioning provider hooks table (see dav_hooks_vsn).  */
602 dav_error *
603 dav_svn__checkout(dav_resource *resource,
604                   int auto_checkout,
605                   int is_unreserved,
606                   int is_fork_ok,
607                   int create_activity,
608                   apr_array_header_t *activities,
609                   dav_resource **working_resource);
610 
611 dav_error *
612 dav_svn__checkin(dav_resource *resource,
613                  int keep_checked_out,
614                  dav_resource **version_resource);
615 
616 
617 /* Helper for reading lock-tokens out of request bodies, by looking
618    for cached body in R->pool's userdata.
619 
620    Return a hash that maps (const char *) absolute fs paths to (const
621    char *) locktokens.  Allocate the hash and all keys/vals in POOL.
622    PATH_PREFIX is the prefix we need to prepend to each relative
623    'lock-path' in the xml in order to create an absolute fs-path.  */
624 dav_error *
625 dav_svn__build_lock_hash(apr_hash_t **locks,
626                          request_rec *r,
627                          const char *path_prefix,
628                          apr_pool_t *pool);
629 
630 
631 /* Helper: push all of the lock-tokens (hash values) in LOCKS into
632    RESOURCE's already-open svn_fs_t. */
633 dav_error *
634 dav_svn__push_locks(dav_resource *resource,
635                     apr_hash_t *locks,
636                     apr_pool_t *pool);
637 
638 
639 extern const dav_hooks_vsn dav_svn__hooks_vsn;
640 
641 
642 /*** liveprops.c ***/
643 
644 extern const dav_liveprop_group dav_svn__liveprop_group;
645 
646 /*
647   LIVE PROPERTY HOOKS
648 
649   These are standard hooks defined by mod_dav. We implement them to expose
650   various live properties on the resources under our control.
651 
652   gather_propsets: appends URIs into the array; the property set URIs are
653                    used to specify which sets of custom properties we
654                    define/expose.
655   find_liveprop: given a namespace and name, return the hooks for the
656                  provider who defines that property.
657   insert_all_liveprops: for a given resource, insert all of the live
658                         properties defined on that resource. The properties
659                         are inserted according to the WHAT parameter.
660 */
661 void dav_svn__gather_propsets(apr_array_header_t *uris);
662 
663 int
664 dav_svn__find_liveprop(const dav_resource *resource,
665                        const char *ns_uri,
666                        const char *name,
667                        const dav_hooks_liveprop **hooks);
668 
669 void
670 dav_svn__insert_all_liveprops(request_rec *r,
671                               const dav_resource *resource,
672                               dav_prop_insert what,
673                               apr_text_header *phdr);
674 
675 
676 /*** merge.c ***/
677 
678 /* Generate the HTTP response body for a successful MERGE. */
679 /* ### more docco */
680 dav_error *
681 dav_svn__merge_response(dav_svn__output *output,
682                         const dav_svn_repos *repos,
683                         svn_revnum_t new_rev,
684                         const char *post_commit_err,
685                         apr_xml_elem *prop_elem,
686                         svn_boolean_t disable_merge_response,
687                         apr_pool_t *pool);
688 
689 
690 /*** reports/ ***/
691 
692 /* The list of Subversion's custom REPORTs. */
693 /* ### should move these report names to a public header to share with
694    ### the client (and third parties). */
695 static const dav_report_elem dav_svn__reports_list[] = {
696   { SVN_XML_NAMESPACE, "update-report" },
697   { SVN_XML_NAMESPACE, "log-report" },
698   { SVN_XML_NAMESPACE, "dated-rev-report" },
699   { SVN_XML_NAMESPACE, "get-locations" },
700   { SVN_XML_NAMESPACE, "get-location-segments" },
701   { SVN_XML_NAMESPACE, "file-revs-report" },
702   { SVN_XML_NAMESPACE, "get-locks-report" },
703   { SVN_XML_NAMESPACE, "replay-report" },
704   { SVN_XML_NAMESPACE, "get-deleted-rev-report" },
705   { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_REPORT },
706   { SVN_XML_NAMESPACE, SVN_DAV__INHERITED_PROPS_REPORT },
707   { SVN_XML_NAMESPACE, "list-report" },
708   { NULL, NULL },
709 };
710 
711 
712 /* The various report handlers, defined in reports/, and used by version.c.  */
713 dav_error *
714 dav_svn__update_report(const dav_resource *resource,
715                        const apr_xml_doc *doc,
716                        dav_svn__output *output);
717 dav_error *
718 dav_svn__log_report(const dav_resource *resource,
719                     const apr_xml_doc *doc,
720                     dav_svn__output *output);
721 dav_error *
722 dav_svn__dated_rev_report(const dav_resource *resource,
723                           const apr_xml_doc *doc,
724                           dav_svn__output *output);
725 dav_error *
726 dav_svn__get_locations_report(const dav_resource *resource,
727                               const apr_xml_doc *doc,
728                               dav_svn__output *output);
729 dav_error *
730 dav_svn__get_location_segments_report(const dav_resource *resource,
731                                       const apr_xml_doc *doc,
732                                       dav_svn__output *output);
733 dav_error *
734 dav_svn__file_revs_report(const dav_resource *resource,
735                           const apr_xml_doc *doc,
736                           dav_svn__output *output);
737 dav_error *
738 dav_svn__replay_report(const dav_resource *resource,
739                        const apr_xml_doc *doc,
740                        dav_svn__output *output);
741 dav_error *
742 dav_svn__get_mergeinfo_report(const dav_resource *resource,
743                               const apr_xml_doc *doc,
744                               dav_svn__output *output);
745 dav_error *
746 dav_svn__get_locks_report(const dav_resource *resource,
747                           const apr_xml_doc *doc,
748                           dav_svn__output *output);
749 
750 dav_error *
751 dav_svn__get_deleted_rev_report(const dav_resource *resource,
752                                 const apr_xml_doc *doc,
753                                 dav_svn__output *output);
754 
755 dav_error *
756 dav_svn__get_inherited_props_report(const dav_resource *resource,
757                                     const apr_xml_doc *doc,
758                                     dav_svn__output *output);
759 
760 dav_error *
761 dav_svn__list_report(const dav_resource *resource,
762                      const apr_xml_doc *doc,
763                      dav_svn__output *output);
764 
765 /*** posts/ ***/
766 
767 /* The various POST handlers, defined in posts/, and used by repos.c.  */
768 dav_error *
769 dav_svn__post_create_txn(const dav_resource *resource,
770                          svn_skel_t *request_skel,
771                          dav_svn__output *output);
772 dav_error *
773 dav_svn__post_create_txn_with_props(const dav_resource *resource,
774                                     svn_skel_t *request_skel,
775                                     dav_svn__output *output);
776 
777 /*** authz.c ***/
778 
779 /* A baton needed by dav_svn__authz_read_func(). */
780 typedef struct dav_svn__authz_read_baton
781 {
782   /* The original request, needed to generate a subrequest. */
783   request_rec *r;
784 
785   /* We need this to construct a URI based on a repository abs path. */
786   const dav_svn_repos *repos;
787 
788 } dav_svn__authz_read_baton;
789 
790 
791 /* Return TRUE iff the current user (as determined by Apache's
792    authentication system) has permission to read PATH in REPOS at REV
793    (where an invalid REV means "HEAD").  This will invoke any authz
794    modules loaded into Apache unless this Subversion location has been
795    configured to bypass those in favor of a direct lookup in the
796    Subversion authz subsystem.  Use POOL for any temporary allocation.
797 */
798 svn_boolean_t
799 dav_svn__allow_read(request_rec *r,
800                     const dav_svn_repos *repos,
801                     const char *path,
802                     svn_revnum_t rev,
803                     apr_pool_t *pool);
804 
805 /* Return TRUE iff the current user (as determined by Apache's
806    authentication system) has permission to read RESOURCE in REV
807    (where an invalid REV means "HEAD").  This will invoke any authz
808    modules loaded into Apache unless this Subversion location has been
809    configured to bypass those in favor of a direct lookup in the
810    Subversion authz subsystem.  Use POOL for any temporary allocation.
811 */
812 svn_boolean_t
813 dav_svn__allow_read_resource(const dav_resource *resource,
814                              svn_revnum_t rev,
815                              apr_pool_t *pool);
816 
817 
818 /* Return TRUE iff the current user (as determined by Apache's
819    authentication system) has permission to read repository REPOS_NAME.
820    This will invoke any authz modules loaded into Apache unless this
821    Subversion location has been configured to bypass those in favor of a
822    direct lookup in the Subversion authz subsystem. Use POOL for any
823    temporary allocation.
824    IMPORTANT: R must be request for DAV_SVN_RESTYPE_PARENTPATH_COLLECTION
825    resource.
826 */
827 svn_boolean_t
828 dav_svn__allow_list_repos(request_rec *r,
829                           const char *repos_name,
830                           apr_pool_t *pool);
831 
832 /* If authz is enabled in the specified BATON, return a read authorization
833    function. Otherwise, return NULL. */
834 svn_repos_authz_func_t
835 dav_svn__authz_read_func(dav_svn__authz_read_baton *baton);
836 
837 
838 /*** util.c ***/
839 
840 /* A wrapper around mod_dav's dav_new_error_tag, mod_dav_svn uses this
841    instead of the mod_dav function to enable special mod_dav_svn specific
842    processing.  See dav_new_error_tag for parameter documentation.
843    Note that DESC may be null (it's hard to track this down from
844    dav_new_error_tag()'s documentation, but see the dav_error type,
845    which says that its desc field may be NULL).
846 
847    If ERROR_ID is 0, SVN_ERR_RA_DAV_REQUEST_FAILED will be used as a
848    default value for the error code.
849 
850    mod_dav is definitive documentation of the parameters, but a
851    guideline to the different error is:
852 
853    STATUS is the HTTP status returned to the client.
854 
855    ERROR_ID is an additional DAV-specific error such as a violation of
856    the DAV rules.  mod_dav.h defines some values but callers can pass
857    others.
858 
859    APRERR is any underlying OS/system error.
860 */
861 dav_error *
862 dav_svn__new_error_svn(apr_pool_t *pool,
863                        int status,
864                        int error_id,
865                        apr_status_t aprerr,
866                        const char *desc);
867 
868 
869 /* A wrapper around mod_dav's dav_new_error, mod_dav_svn uses this
870    instead of the mod_dav function to enable special mod_dav_svn specific
871    processing.  See dav_svn__new_error_svn for additional details.
872 */
873 dav_error *
874 dav_svn__new_error(apr_pool_t *pool,
875                    int status,
876                    int error_id,
877                    apr_status_t aprerr,
878                    const char *desc);
879 
880 
881 /* Convert an svn_error_t into a dav_error, pushing another error based on
882    MESSAGE if MESSAGE is not NULL.  Use the provided HTTP status for the
883    DAV errors.  Allocate new DAV errors from POOL.
884 
885    NOTE: this function destroys (cleanly, of course) SERR after it has
886    copied/converted its data to the new DAV error.
887 
888    NOTE: MESSAGE needs to hang around for the lifetime of the error since
889    the current implementation doesn't copy it!  Lots of callers pass static
890    string constant. */
891 dav_error *
892 dav_svn__convert_err(svn_error_t *serr,
893                      int status,
894                      const char *message,
895                      apr_pool_t *pool);
896 
897 
898 /* Compare (PATH in ROOT) to (PATH in ROOT/PATH's created_rev).
899 
900    If these nodes are identical, then return the created_rev.
901 
902    If the nodes aren't identical, or if PATH simply doesn't exist in
903    the created_rev, then return the revision represented by ROOT.
904 
905    (This is a helper to functions that want to build version-urls and
906     use the CR if possible.) */
907 svn_revnum_t
908 dav_svn__get_safe_cr(svn_fs_root_t *root, const char *path, apr_pool_t *pool);
909 
910 
911 /* Construct various kinds of URIs.
912 
913    REPOS is always required, as all URIs will be built to refer to elements
914    within that repository. WHAT specifies the type of URI to build. The
915    ADD_HREF flag determines whether the URI is to be wrapped inside of
916    <D:href>uri</D:href> elements (for inclusion in a response).
917 
918    Different pieces of information are required for the various URI types:
919 
920    ACT_COLLECTION: no additional params required
921    BASELINE:       REVISION should be specified
922    BC:             REVISION should be specified
923    PUBLIC:         PATH should be specified with a leading slash
924    VERSION:        REVISION and PATH should be specified
925    VCC:            no additional params required
926 */
927 enum dav_svn__build_what {
928   DAV_SVN__BUILD_URI_ACT_COLLECTION, /* the collection of activities */
929   DAV_SVN__BUILD_URI_BASELINE,   /* a Baseline */
930   DAV_SVN__BUILD_URI_BC,         /* a Baseline Collection */
931   DAV_SVN__BUILD_URI_PUBLIC,     /* the "public" VCR */
932   DAV_SVN__BUILD_URI_VERSION,    /* a Version Resource */
933   DAV_SVN__BUILD_URI_VCC,        /* a Version Controlled Configuration */
934   DAV_SVN__BUILD_URI_REVROOT     /* HTTPv2: Revision Root resource */
935 };
936 
937 const char *
938 dav_svn__build_uri(const dav_svn_repos *repos,
939                    enum dav_svn__build_what what,
940                    svn_revnum_t revision,
941                    const char *path,
942                    svn_boolean_t add_href,
943                    apr_pool_t *pool);
944 
945 
946 /* Simple parsing of a URI. This is used for URIs which appear within a
947    request body. It enables us to verify and break out the necessary pieces
948    to figure out what is being referred to.
949 
950    ### this is horribly duplicative with the parsing functions in repos.c
951    ### for now, this implements only a minor subset of the full range of
952    ### URIs which we may need to parse. it also ignores any scheme, host,
953    ### and port in the URI and simply assumes it refers to the same server.
954 */
955 typedef struct dav_svn__uri_info {
956   svn_revnum_t rev;
957   const char *repos_path;
958   const char *activity_id;
959 } dav_svn__uri_info;
960 
961 svn_error_t *
962 dav_svn__simple_parse_uri(dav_svn__uri_info *info,
963                           const dav_resource *relative,
964                           const char *uri,
965                           apr_pool_t *pool);
966 
967 /* Test the request R to determine if we should return the list of
968  * repositories at the parent path.  Only true if SVNListParentPath directive
969  * is 'on' and the request is for our configured root path. */
970 svn_boolean_t
971 dav_svn__is_parentpath_list(request_rec *r);
972 
973 
974 int dav_svn__find_ns(const apr_array_header_t *namespaces, const char *uri);
975 
976 
977 
978 /*** Brigade I/O wrappers ***/
979 
980 /* Write LEN bytes from DATA to OUTPUT using BB.  */
981 svn_error_t *dav_svn__brigade_write(apr_bucket_brigade *bb,
982                                     dav_svn__output *output,
983                                     const char *buf,
984                                     apr_size_t len);
985 
986 /* Write NULL-terminated string STR to OUTPUT using BB.  */
987 svn_error_t *dav_svn__brigade_puts(apr_bucket_brigade *bb,
988                                    dav_svn__output *output,
989                                    const char *str);
990 
991 
992 /* Write data to OUTPUT using BB, using FMT as the output format string.  */
993 svn_error_t *dav_svn__brigade_printf(apr_bucket_brigade *bb,
994                                      dav_svn__output *output,
995                                      const char *fmt,
996                                      ...)
997   __attribute__((format(printf, 3, 4)));
998 
999 /* Write an unspecified number of strings to OUTPUT using BB.  */
1000 svn_error_t *dav_svn__brigade_putstrs(apr_bucket_brigade *bb,
1001                                       dav_svn__output *output,
1002                                       ...) SVN_NEEDS_SENTINEL_NULL;
1003 
1004 
1005 
1006 
1007 /* Test PATH for canonicalness (defined as "what won't make the
1008    svn_path_* functions immediately explode"), returning an
1009    HTTP_BAD_REQUEST error tag if the test fails. */
1010 dav_error *dav_svn__test_canonical(const char *path, apr_pool_t *pool);
1011 
1012 
1013 /* Convert @a serr into a dav_error.  If @a new_msg is non-NULL, use
1014    @a new_msg in the returned error, and write the original
1015    @a serr->message to httpd's log.  Destroy the passed-in @a serr,
1016    similarly to dav_svn__convert_err().
1017 
1018    @a new_msg is usually a "sanitized" version of @a serr->message.
1019    That is, if @a serr->message contains security-sensitive data,
1020    @a new_msg does not.
1021 
1022    The purpose of sanitization is to prevent security-sensitive data
1023    from being transmitted over the network to the client.  The error
1024    messages produced by various APIs (e.g., svn_fs, svn_repos) may
1025    contain security-sensitive data such as the actual server file
1026    system's path to the repository.  We don't want to send that to the
1027    client, but we do want to log the real error on the server side.
1028  */
1029 dav_error *
1030 dav_svn__sanitize_error(svn_error_t *serr,
1031                         const char *new_msg,
1032                         int http_status,
1033                         request_rec *r);
1034 
1035 
1036 /* Return a writable generic stream that will encode its output to base64
1037    and send it to OUTPUT using BB.  Allocate the stream in POOL. */
1038 svn_stream_t *
1039 dav_svn__make_base64_output_stream(apr_bucket_brigade *bb,
1040                                    dav_svn__output *output,
1041                                    apr_pool_t *pool);
1042 
1043 /* In INFO->r->subprocess_env set "SVN-ACTION" to LINE, "SVN-REPOS" to
1044  * INFO->repos->fs_path, and "SVN-REPOS-NAME" to INFO->repos->repo_basename. */
1045 void
1046 dav_svn__operational_log(struct dav_resource_private *info, const char *line);
1047 
1048 /* Flush BB if it's okay and useful to do so, but treat PREFERRED_ERR
1049  * as a more important error to return (if it is non-NULL).
1050  *
1051  * This is intended to be used at the end of response processing,
1052  * probably called as a direct return generator, like so:
1053  *
1054  *   return dav_svn__final_flush_or_error(r, bb, output, derr, resource->pool);
1055  *
1056  * SOME BACKGROUND INFO:
1057  *
1058  * We don't flush the brigade unless there's something in it to
1059  * flush; that way, we have the opportunity to package a dav_error up
1060  * for transmission back to the client.
1061  *
1062  * To understand this, see mod_dav.c:dav_method_report(): as long as
1063  * it doesn't think we've sent anything to the client, it'll send
1064  * the real error, which is what we'd prefer.  This situation is
1065  * described in httpd-2.2.6/modules/dav/main/mod_dav.c, line 4066,
1066  * in the comment in dav_method_report() that says:
1067  *
1068  *    If an error occurred during the report delivery, there's
1069  *    basically nothing we can do but abort the connection and
1070  *    log an error.  This is one of the limitations of HTTP; it
1071  *    needs to "know" the entire status of the response before
1072  *    generating it, which is just impossible in these streamy
1073  *    response situations.
1074  *
1075  * In other words, flushing the brigade causes r->sent_bodyct (see
1076  * dav_method_report()) to become non-zero, even if we hadn't tried to
1077  * send any data to the brigade yet.  So we don't flush unless data
1078  * was actually sent.
1079  */
1080 dav_error *
1081 dav_svn__final_flush_or_error(request_rec *r, apr_bucket_brigade *bb,
1082                               dav_svn__output *output,
1083                               dav_error *preferred_err,
1084                               apr_pool_t *pool);
1085 
1086 /* Log a DAV error response.
1087  *
1088  * NOTE: Copied from mod_dav's dav_log_err which is not public.
1089  */
1090 void dav_svn__log_err(request_rec *r,
1091                       dav_error *err,
1092                       int level);
1093 
1094 /* Send a "standardized" DAV error response based on the ERR's
1095  * namespace and tag.
1096  *
1097  * NOTE:  This was copied pretty much directory from mod_dav's
1098  * dav_error_response_tag() function which is, sadly, not public.
1099  */
1100 int dav_svn__error_response_tag(request_rec *r, dav_error *err);
1101 
1102 
1103 /* Set *SKEL to a parsed skel read from the body of request R, and
1104  * allocated in POOL.
1105  */
1106 int dav_svn__parse_request_skel(svn_skel_t **skel, request_rec *r,
1107                                 apr_pool_t *pool);
1108 
1109 /* Set *YOUNGEST_P to the number of the youngest revision in REPOS.
1110  *
1111  * Youngest revision will be cached in REPOS->YOUNGEST_REV to avoid
1112  * fetching the youngest revision multiple times during proccessing
1113  * the request.
1114  *
1115  * Uses SCRATCH_POOL for temporary allocations.
1116  */
1117 svn_error_t *
1118 dav_svn__get_youngest_rev(svn_revnum_t *youngest_p,
1119                           dav_svn_repos *repos,
1120                           apr_pool_t *scratch_pool);
1121 
1122 /* Return the liveprop-encoded form of AUTHOR, allocated in RESULT_POOL.
1123  * If IS_SVN_CLIENT is set, assume that the data will be sent to a SVN
1124  * client.  This mainly sanitizes AUTHOR strings with control chars in
1125  * them without converting them to escape sequences etc.
1126  *
1127  * Use SCRATCH_POOL for temporary allocations.
1128  */
1129 const char *
1130 dav_svn__fuzzy_escape_author(const char *author,
1131                              svn_boolean_t is_svn_client,
1132                              apr_pool_t *result_pool,
1133                              apr_pool_t *scratch_pool);
1134 
1135 /*** mirror.c ***/
1136 
1137 /* Perform the fixup hook for the R request.  */
1138 int dav_svn__proxy_request_fixup(request_rec *r);
1139 
1140 /* An Apache input filter which rewrites the locations in headers and
1141    request body.  It reads from filter F using BB data, MODE mode, BLOCK
1142    blocking strategy, and READBYTES. */
1143 apr_status_t dav_svn__location_in_filter(ap_filter_t *f,
1144                                          apr_bucket_brigade *bb,
1145                                          ap_input_mode_t mode,
1146                                          apr_read_type_e block,
1147                                          apr_off_t readbytes);
1148 
1149 /* An Apache output filter F which rewrites the response headers for
1150  * location headers.  It will modify the stream in BB. */
1151 apr_status_t dav_svn__location_header_filter(ap_filter_t *f,
1152                                              apr_bucket_brigade *bb);
1153 
1154 /* An Apache output filter F which rewrites the response body for
1155  * location headers.  It will modify the stream in BB. */
1156 apr_status_t dav_svn__location_body_filter(ap_filter_t *f,
1157                                            apr_bucket_brigade *bb);
1158 
1159 
1160 #ifdef __cplusplus
1161 }
1162 #endif /* __cplusplus */
1163 
1164 #endif /* DAV_SVN_H */
1165