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