summaryrefslogtreecommitdiff
path: root/subversion/mod_dav_svn/dav_svn.h
blob: 34efccb129b0469df4bc529d59c00668330df9d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
/*
 * 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 tranaction
     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;
};


/* 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 proccessing
 * 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 */