summaryrefslogtreecommitdiff
path: root/subversion/mod_dav_svn
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
commitcf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch)
treeda27775a2161723ef342e91af41a8b51fedef405 /subversion/mod_dav_svn
parentbb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff)
downloadsubversion-tarball-master.tar.gz
Diffstat (limited to 'subversion/mod_dav_svn')
-rw-r--r--subversion/mod_dav_svn/activity.c16
-rw-r--r--subversion/mod_dav_svn/authz.c5
-rw-r--r--subversion/mod_dav_svn/dav_svn.h97
-rw-r--r--subversion/mod_dav_svn/deadprops.c8
-rw-r--r--subversion/mod_dav_svn/liveprops.c73
-rw-r--r--subversion/mod_dav_svn/lock.c96
-rw-r--r--subversion/mod_dav_svn/merge.c95
-rw-r--r--subversion/mod_dav_svn/mirror.c10
-rw-r--r--subversion/mod_dav_svn/mod_dav_svn.c145
-rw-r--r--subversion/mod_dav_svn/posts/create_txn.c4
-rw-r--r--subversion/mod_dav_svn/reports/dated-rev.c12
-rw-r--r--subversion/mod_dav_svn/reports/deleted-rev.c24
-rw-r--r--subversion/mod_dav_svn/reports/file-revs.c34
-rw-r--r--subversion/mod_dav_svn/reports/get-location-segments.c45
-rw-r--r--subversion/mod_dav_svn/reports/get-locations.c57
-rw-r--r--subversion/mod_dav_svn/reports/get-locks.c76
-rw-r--r--subversion/mod_dav_svn/reports/inherited-props.c19
-rw-r--r--subversion/mod_dav_svn/reports/log.c120
-rw-r--r--subversion/mod_dav_svn/reports/mergeinfo.c17
-rw-r--r--subversion/mod_dav_svn/reports/replay.c34
-rw-r--r--subversion/mod_dav_svn/reports/update.c63
-rw-r--r--subversion/mod_dav_svn/repos.c862
-rw-r--r--subversion/mod_dav_svn/status.c115
-rw-r--r--subversion/mod_dav_svn/util.c266
-rw-r--r--subversion/mod_dav_svn/version.c260
25 files changed, 1546 insertions, 1007 deletions
diff --git a/subversion/mod_dav_svn/activity.c b/subversion/mod_dav_svn/activity.c
index 895c4cf..1c779d2 100644
--- a/subversion/mod_dav_svn/activity.c
+++ b/subversion/mod_dav_svn/activity.c
@@ -193,7 +193,6 @@ dav_svn__store_activity(const dav_svn_repos *repos,
const char *txn_name)
{
const char *final_path;
- const char *tmp_path;
const char *activity_contents;
svn_error_t *err;
@@ -209,11 +208,9 @@ dav_svn__store_activity(const dav_svn_repos *repos,
activity_contents = apr_psprintf(repos->pool, "%s\n%s\n",
txn_name, activity_id);
- /* ### is there another directory we already have and can write to? */
- err = svn_io_write_unique(&tmp_path,
- svn_dirent_dirname(final_path, repos->pool),
+ err = svn_io_write_atomic(final_path,
activity_contents, strlen(activity_contents),
- svn_io_file_del_none, repos->pool);
+ NULL /* copy_perms path */, repos->pool);
if (err)
{
svn_error_t *serr = svn_error_quick_wrap(err,
@@ -225,15 +222,6 @@ dav_svn__store_activity(const dav_svn_repos *repos,
repos->pool);
}
- err = svn_io_file_rename(tmp_path, final_path, repos->pool);
- if (err)
- {
- svn_error_clear(svn_io_remove_file2(tmp_path, TRUE, repos->pool));
- return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
- "could not replace files.",
- repos->pool);
- }
-
return NULL;
}
diff --git a/subversion/mod_dav_svn/authz.c b/subversion/mod_dav_svn/authz.c
index 27763b0..9b5c7d6 100644
--- a/subversion/mod_dav_svn/authz.c
+++ b/subversion/mod_dav_svn/authz.c
@@ -57,7 +57,7 @@ dav_svn__allow_read(request_rec *r,
/* Sometimes we get paths that do not start with '/' and
hence below uri concatenation would lead to wrong uris .*/
if (path && path[0] != '/')
- path = apr_pstrcat(pool, "/", path, NULL);
+ path = apr_pstrcat(pool, "/", path, SVN_VA_NULL);
/* If bypass is specified and authz has exported the provider.
Otherwise, we fall through to the full version. This should be
@@ -80,7 +80,8 @@ dav_svn__allow_read(request_rec *r,
uri_type = DAV_SVN__BUILD_URI_PUBLIC;
/* Build a Version Resource uri representing (rev, path). */
- uri = dav_svn__build_uri(repos, uri_type, rev, path, FALSE, pool);
+ uri = dav_svn__build_uri(repos, uri_type, rev, path, FALSE /* add_href */,
+ pool);
/* Check if GET would work against this uri. */
subreq = ap_sub_req_method_uri("GET", uri, r, r->output_filters);
diff --git a/subversion/mod_dav_svn/dav_svn.h b/subversion/mod_dav_svn/dav_svn.h
index 8786518..9d11a0a 100644
--- a/subversion/mod_dav_svn/dav_svn.h
+++ b/subversion/mod_dav_svn/dav_svn.h
@@ -54,7 +54,7 @@ extern "C" {
/* Option values for SVNAllowBulkUpdates. Note that
it's important that CONF_BULKUPD_DEFAULT is 0 to make
- dav_svn_merge_dir_config do the right thing. */
+ merge_dir_config in mod_dav_svn do the right thing. */
typedef enum dav_svn__bulk_upd_conf {
CONF_BULKUPD_DEFAULT,
CONF_BULKUPD_ON,
@@ -329,6 +329,10 @@ 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);
+/* 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.
*/
@@ -442,6 +446,40 @@ 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 ***/
@@ -482,6 +520,8 @@ dav_svn__store_activity(const dav_svn_repos *repos,
/* 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 ***/
@@ -628,7 +668,7 @@ dav_svn__insert_all_liveprops(request_rec *r,
/* Generate the HTTP response body for a successful MERGE. */
/* ### more docco */
dav_error *
-dav_svn__merge_response(ap_filter_t *output,
+dav_svn__merge_response(dav_svn__output *output,
const dav_svn_repos *repos,
svn_revnum_t new_rev,
const char *post_commit_err,
@@ -662,49 +702,49 @@ static const dav_report_elem dav_svn__reports_list[] = {
dav_error *
dav_svn__update_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__log_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__dated_rev_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__get_locations_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__get_location_segments_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__file_revs_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__replay_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__get_mergeinfo_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__get_locks_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__get_deleted_rev_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__get_inherited_props_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output);
+ dav_svn__output *output);
/*** posts/ ***/
@@ -712,11 +752,11 @@ dav_svn__get_inherited_props_report(const dav_resource *resource,
dav_error *
dav_svn__post_create_txn(const dav_resource *resource,
svn_skel_t *request_skel,
- ap_filter_t *output);
+ dav_svn__output *output);
dav_error *
dav_svn__post_create_txn_with_props(const dav_resource *resource,
svn_skel_t *request_skel,
- ap_filter_t *output);
+ dav_svn__output *output);
/*** authz.c ***/
@@ -792,12 +832,10 @@ dav_svn__authz_read_func(dav_svn__authz_read_baton *baton);
default value for the error code.
*/
dav_error *
-dav_svn__new_error_tag(apr_pool_t *pool,
+dav_svn__new_error_svn(apr_pool_t *pool,
int status,
int error_id,
- const char *desc,
- const char *namespace,
- const char *tagname);
+ const char *desc);
/* A wrapper around mod_dav's dav_new_error, mod_dav_svn uses this
@@ -878,7 +916,7 @@ dav_svn__build_uri(const dav_svn_repos *repos,
enum dav_svn__build_what what,
svn_revnum_t revision,
const char *path,
- int add_href,
+ svn_boolean_t add_href,
apr_pool_t *pool);
@@ -918,23 +956,28 @@ int dav_svn__find_ns(const apr_array_header_t *namespaces, const char *uri);
/* Write LEN bytes from DATA to OUTPUT using BB. */
svn_error_t *dav_svn__brigade_write(apr_bucket_brigade *bb,
- ap_filter_t *output,
+ 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,
- ap_filter_t *output,
+ 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,
- ap_filter_t *output,
+ 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;
+
@@ -968,11 +1011,10 @@ dav_svn__sanitize_error(svn_error_t *serr,
/* Return a writable generic stream that will encode its output to base64
- and send it to the Apache filter OUTPUT using BB. Allocate the stream in
- POOL. */
+ 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,
- ap_filter_t *output,
+ dav_svn__output *output,
apr_pool_t *pool);
/* In INFO->r->subprocess_env set "SVN-ACTION" to LINE, "SVN-REPOS" to
@@ -1014,7 +1056,8 @@ dav_svn__operational_log(struct dav_resource_private *info, const char *line);
*/
dav_error *
dav_svn__final_flush_or_error(request_rec *r, apr_bucket_brigade *bb,
- ap_filter_t *output, dav_error *preferred_err,
+ dav_svn__output *output,
+ dav_error *preferred_err,
apr_pool_t *pool);
/* Log a DAV error response.
diff --git a/subversion/mod_dav_svn/deadprops.c b/subversion/mod_dav_svn/deadprops.c
index 5d228a4..94e1a69 100644
--- a/subversion/mod_dav_svn/deadprops.c
+++ b/subversion/mod_dav_svn/deadprops.c
@@ -339,7 +339,7 @@ db_open(apr_pool_t *p,
db->p = svn_pool_create(p);
/* ### temp hack */
- db->work = svn_stringbuf_ncreate("", 0, db->p);
+ db->work = svn_stringbuf_create_empty(db->p);
/* make our path-based authz callback available to svn_repos_* funcs. */
arb = apr_pcalloc(p, sizeof(*arb));
@@ -654,16 +654,14 @@ static void get_name(dav_db *db, dav_prop_name *pname)
}
else
{
- const void *name;
-
- apr_hash_this(db->hi, &name, NULL, NULL);
+ const char *name = apr_hash_this_key(db->hi);
#define PREFIX_LEN (sizeof(SVN_PROP_PREFIX) - 1)
if (strncmp(name, SVN_PROP_PREFIX, PREFIX_LEN) == 0)
#undef PREFIX_LEN
{
pname->ns = SVN_DAV_PROP_NS_SVN;
- pname->name = (const char *)name + 4;
+ pname->name = name + 4;
}
else
{
diff --git a/subversion/mod_dav_svn/liveprops.c b/subversion/mod_dav_svn/liveprops.c
index 725ee92..384a810 100644
--- a/subversion/mod_dav_svn/liveprops.c
+++ b/subversion/mod_dav_svn/liveprops.c
@@ -36,6 +36,7 @@
#include "svn_time.h"
#include "svn_dav.h"
#include "svn_props.h"
+#include "svn_ctype.h"
#include "private/svn_dav_protocol.h"
@@ -422,7 +423,43 @@ insert_prop_internal(const dav_resource *resource,
if (last_author == NULL)
return DAV_PROP_INSERT_NOTDEF;
- value = apr_xml_quote_string(scratch_pool, last_author->data, 1);
+ if (svn_xml_is_xml_safe(last_author->data, last_author->len)
+ || !resource->info->repos->is_svn_client)
+ value = apr_xml_quote_string(scratch_pool, last_author->data, 1);
+ else
+ {
+ /* We are talking to a Subversion client, which will (like any proper
+ xml parser) error out if we produce control characters in XML.
+
+ However Subversion clients process both the generic
+ <creator-displayname /> as the custom element for svn:author.
+
+ Let's skip outputting the invalid characters here to make the XML
+ valid, so clients can see the custom element.
+
+ Subversion Clients will then either use a slightly invalid
+ author (unlikely) or more likely use the second result, which
+ will be transferred with full escaping capabilities.
+
+ We have tests in place to assert proper behavior over the RA layer.
+ */
+ apr_size_t i;
+ svn_stringbuf_t *buf;
+
+ buf = svn_stringbuf_create_from_string(last_author, scratch_pool);
+
+ for (i = 0; i < buf->len; i++)
+ {
+ char c = buf->data[i];
+
+ if (svn_ctype_iscntrl(c))
+ {
+ svn_stringbuf_remove(buf, i--, 1);
+ }
+ }
+
+ value = apr_xml_quote_string(scratch_pool, buf->data, 1);
+ }
break;
}
@@ -549,7 +586,7 @@ insert_prop_internal(const dav_resource *resource,
return DAV_PROP_INSERT_NOTSUPP;
value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_BC,
resource->info->root.rev, NULL,
- 1 /* add_href */, scratch_pool);
+ TRUE /* add_href */, scratch_pool);
break;
case DAV_PROPID_checked_in:
@@ -578,7 +615,8 @@ insert_prop_internal(const dav_resource *resource,
}
s = dav_svn__build_uri(resource->info->repos,
DAV_SVN__BUILD_URI_BASELINE,
- revnum, NULL, 0 /* add_href */, scratch_pool);
+ revnum, NULL, FALSE /* add_href */,
+ scratch_pool);
value = apr_psprintf(scratch_pool, "<D:href>%s</D:href>",
apr_xml_quote_string(scratch_pool, s, 1));
}
@@ -596,7 +634,7 @@ insert_prop_internal(const dav_resource *resource,
s = dav_svn__build_uri(resource->info->repos,
DAV_SVN__BUILD_URI_VERSION,
rev_to_use, resource->info->repos_path,
- 0 /* add_href */, scratch_pool);
+ FALSE /* add_href */, scratch_pool);
value = apr_psprintf(scratch_pool, "<D:href>%s</D:href>",
apr_xml_quote_string(scratch_pool, s, 1));
}
@@ -610,7 +648,7 @@ insert_prop_internal(const dav_resource *resource,
return DAV_PROP_INSERT_NOTSUPP;
value = dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_VCC,
SVN_IGNORED_REVNUM, NULL,
- 1 /* add_href */, scratch_pool);
+ TRUE /* add_href */, scratch_pool);
break;
case DAV_PROPID_version_name:
@@ -749,20 +787,30 @@ insert_prop_internal(const dav_resource *resource,
case SVN_PROPID_deadprop_count:
{
- unsigned int propcount;
- apr_hash_t *proplist;
+ svn_boolean_t has_props;
if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
return DAV_PROP_INSERT_NOTSUPP;
- serr = svn_fs_node_proplist(&proplist,
- resource->info->root.root,
- resource->info->repos_path, scratch_pool);
+ /* Retrieving the actual properties is quite expensive while
+ svn clients only want to know if there are properties, by
+ using this svn defined property.
+
+ Our and and SvnKit's implementation of the ra layer check
+ for '> 0' to provide the boolean if the node has custom
+ properties or not, so starting with 1.9 we just provide
+ "1" or "0".
+ */
+ serr = svn_fs_node_has_props(&has_props,
+ resource->info->root.root,
+ resource->info->repos_path,
+ scratch_pool);
+
if (serr != NULL)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err,
resource->info->r,
- "Can't fetch proplist of '%s': "
+ "Can't fetch has properties on '%s': "
"%s",
resource->info->repos_path,
serr->message);
@@ -771,8 +819,7 @@ insert_prop_internal(const dav_resource *resource,
break;
}
- propcount = apr_hash_count(proplist);
- value = apr_psprintf(scratch_pool, "%u", propcount);
+ value = has_props ? "1" : "0";
break;
}
diff --git a/subversion/mod_dav_svn/lock.c b/subversion/mod_dav_svn/lock.c
index 68d6de5..06c038a 100644
--- a/subversion/mod_dav_svn/lock.c
+++ b/subversion/mod_dav_svn/lock.c
@@ -92,7 +92,7 @@ svn_lock_to_dav_lock(dav_lock **dlock,
"<D:owner xmlns:D=\"DAV:\">",
apr_xml_quote_string(pool,
slock->comment, 1),
- "</D:owner>", (char *)NULL);
+ "</D:owner>", SVN_VA_NULL);
}
else
{
@@ -134,7 +134,7 @@ unescape_xml(const char **output,
apr_xml_doc *xml_doc;
apr_status_t apr_err;
const char *xml_input = apr_pstrcat
- (pool, "<?xml version=\"1.0\" encoding=\"utf-8\"?>", input, (char *)NULL);
+ (pool, "<?xml version=\"1.0\" encoding=\"utf-8\"?>", input, SVN_VA_NULL);
apr_err = apr_xml_parser_feed(xml_parser, xml_input, strlen(xml_input));
if (!apr_err)
@@ -274,8 +274,13 @@ parse_locktoken(apr_pool_t *pool,
static const char *
format_locktoken(apr_pool_t *p, const dav_locktoken *locktoken)
{
- /* libsvn_fs already produces a valid locktoken URI. */
- return apr_pstrdup(p, locktoken->uuid_str);
+ svn_stringbuf_t *formatted
+ = svn_stringbuf_create_ensure(strlen(locktoken->uuid_str), p);
+
+ /* libsvn_fs produces a locktoken URI that will be valid XML when
+ escaped. */
+ svn_xml_escape_cdata_cstring(&formatted, locktoken->uuid_str, p);
+ return formatted->data;
}
@@ -782,7 +787,31 @@ append_locks(dav_lockdb *lockdb,
DAV_ERR_LOCK_SAVE_LOCK,
"Anonymous lock creation is not allowed.");
}
- else if (serr && (serr->apr_err == SVN_ERR_REPOS_HOOK_FAILURE ||
+ else if (serr && serr->apr_err == SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED)
+ {
+ /* The lock was created in the repository, so we should report the node
+ as locked to the client */
+
+ /* First log the hook failure, for diagnostics. This clears serr */
+ dav_svn__log_err(info->r,
+ dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Post lock hook failure.",
+ resource->pool),
+ APLOG_WARNING);
+
+ /* How can we report the error to the client?
+
+ We can't return an error code, as that would make it impossible
+ to return the lock details?
+
+ Add yet another custom header?
+ Just an header doesn't handle a full error chain...
+
+ ### Current behavior: we don't report an error.
+ */
+
+ }
+ else if (serr && (svn_error_find_cause(serr, SVN_ERR_REPOS_HOOK_FAILURE) ||
serr->apr_err == SVN_ERR_FS_NO_SUCH_LOCK ||
serr->apr_err == SVN_ERR_FS_LOCK_EXPIRED ||
SVN_ERR_IS_LOCK_ERROR(serr)))
@@ -838,14 +867,14 @@ remove_lock(dav_lockdb *lockdb,
/* Sanity check: if the resource has no associated path in the fs,
then there's nothing to do. */
if (! resource->info->repos_path)
- return 0;
+ return NULL;
/* Another easy out: if an svn client sent a 'keep_locks' header
(typically in a DELETE request, as part of 'svn commit
--no-unlock'), then ignore dav_method_delete()'s attempt to
unconditionally remove the lock. */
if (info->keep_locks)
- return 0;
+ return NULL;
/* If the resource's fs path is unreadable, we don't allow a lock to
be removed from it. */
@@ -892,6 +921,22 @@ remove_lock(dav_lockdb *lockdb,
DAV_ERR_LOCK_SAVE_LOCK,
"Anonymous lock removal is not allowed.");
}
+ else if (serr && serr->apr_err == SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED
+ && !resource->info->repos->is_svn_client)
+ {
+ /* Generic DAV clients don't understand the specific error code we
+ would produce here as being just a warning, so lets produce a
+ success result. We removed the lock anyway. */
+
+ /* First log the hook failure, for diagnostics. This clears serr */
+ dav_svn__log_err(info->r,
+ dav_svn__convert_err(serr,
+ HTTP_INTERNAL_SERVER_ERROR,
+ "Post unlock hook failure.",
+ resource->pool),
+ APLOG_WARNING);
+
+ }
else if (serr)
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Failed to remove a lock.",
@@ -905,10 +950,41 @@ remove_lock(dav_lockdb *lockdb,
resource->info->r->pool));
}
- return 0;
+ return NULL;
+}
+
+static dav_error *
+remove_lock_svn_output(dav_lockdb *lockdb,
+ const dav_resource *resource,
+ const dav_locktoken *locktoken)
+{
+ dav_error *derr = remove_lock(lockdb, resource, locktoken);
+ int status;
+
+ if (!derr
+ || !resource->info->repos
+ || !resource->info->repos->is_svn_client
+ || (strcmp(lockdb->info->r->method, "UNLOCK") != 0))
+ return derr;
+
+ /* Ok, we have a nice error chain but mod_dav doesn't offer us a way to
+ present it to the client as it will only use the status code for
+ generating a standard error...
+
+ Luckily the unlock processing for the "UNLOCK" method is very simple:
+ call this function and return the result.
+
+ That allows us to just force a response and tell httpd that we are done */
+ status = dav_svn__error_response_tag(lockdb->info->r, derr);
+
+ /* status = DONE */
+
+ /* And push an error that will make mod_dav just report that it is done */
+ return dav_push_error(resource->pool, status, derr->error_id, NULL, derr);
}
+
/*
** Refresh all locks, found on the specified resource, which has a
** locktoken in the provided list.
@@ -980,7 +1056,7 @@ refresh_locks(dav_lockdb *lockdb,
DAV_ERR_LOCK_SAVE_LOCK,
"Anonymous lock refreshing is not allowed.");
}
- else if (serr && (serr->apr_err == SVN_ERR_REPOS_HOOK_FAILURE ||
+ else if (serr && (svn_error_find_cause(serr, SVN_ERR_REPOS_HOOK_FAILURE) ||
serr->apr_err == SVN_ERR_FS_NO_SUCH_LOCK ||
serr->apr_err == SVN_ERR_FS_LOCK_EXPIRED ||
SVN_ERR_IS_LOCK_ERROR(serr)))
@@ -1014,7 +1090,7 @@ const dav_hooks_locks dav_svn__hooks_locks = {
find_lock,
has_locks,
append_locks,
- remove_lock,
+ remove_lock_svn_output,
refresh_locks,
NULL,
NULL /* hook structure context */
diff --git a/subversion/mod_dav_svn/merge.c b/subversion/mod_dav_svn/merge.c
index 3d6d80b..5407a0f 100644
--- a/subversion/mod_dav_svn/merge.c
+++ b/subversion/mod_dav_svn/merge.c
@@ -72,21 +72,20 @@ send_response(const dav_svn_repos *repos,
svn_fs_root_t *root,
const char *path,
svn_boolean_t is_dir,
- ap_filter_t *output,
+ dav_svn__output *output,
apr_bucket_brigade *bb,
apr_pool_t *pool)
{
const char *href;
const char *vsn_url;
- apr_status_t status;
svn_revnum_t rev_to_use;
href = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_PUBLIC,
SVN_IGNORED_REVNUM, path, 0 /* add_href */, pool);
rev_to_use = dav_svn__get_safe_cr(root, path, pool);
vsn_url = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_VERSION,
- rev_to_use, path, 0 /* add_href */, pool);
- status = ap_fputstrs(output, bb,
+ rev_to_use, path, FALSE /* add_href */, pool);
+ SVN_ERR(dav_svn__brigade_putstrs(bb, output,
"<D:response>" DEBUG_CR
"<D:href>",
apr_xml_quote_string(pool, href, 1),
@@ -103,9 +102,7 @@ send_response(const dav_svn_repos *repos,
"<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
"</D:propstat>" DEBUG_CR
"</D:response>" DEBUG_CR,
- NULL);
- if (status != APR_SUCCESS)
- return svn_error_wrap_apr(status, "Can't write response to output");
+ SVN_VA_NULL));
return SVN_NO_ERROR;
}
@@ -115,7 +112,7 @@ static svn_error_t *
do_resources(const dav_svn_repos *repos,
svn_fs_root_t *root,
svn_revnum_t revision,
- ap_filter_t *output,
+ dav_svn__output *output,
apr_bucket_brigade *bb,
apr_pool_t *pool)
{
@@ -136,12 +133,13 @@ do_resources(const dav_svn_repos *repos,
const void *key;
void *val;
const char *path;
+ apr_ssize_t path_len;
svn_fs_path_change2_t *change;
svn_boolean_t send_self;
svn_boolean_t send_parent;
svn_pool_clear(subpool);
- apr_hash_this(hi, &key, NULL, &val);
+ apr_hash_this(hi, &key, &path_len, &val);
path = key;
change = val;
@@ -170,14 +168,14 @@ do_resources(const dav_svn_repos *repos,
{
/* If we haven't already sent this path, send it (and then
remember that we sent it). */
- if (! svn_hash_gets(sent, path))
+ if (! apr_hash_get(sent, path, path_len))
{
svn_node_kind_t kind;
SVN_ERR(svn_fs_check_path(&kind, root, path, subpool));
SVN_ERR(send_response(repos, root, path,
kind == svn_node_dir,
output, bb, subpool));
- svn_hash_sets(sent, path, (void *)1);
+ apr_hash_set(sent, path, path_len, (void *)1);
}
}
if (send_parent)
@@ -208,7 +206,7 @@ do_resources(const dav_svn_repos *repos,
*/
dav_error *
-dav_svn__merge_response(ap_filter_t *output,
+dav_svn__merge_response(dav_svn__output *output,
const dav_svn_repos *repos,
svn_revnum_t new_rev,
const char *post_commit_err,
@@ -224,7 +222,6 @@ dav_svn__merge_response(ap_filter_t *output,
svn_string_t *creationdate, *creator_displayname;
const char *post_commit_err_elem = NULL,
*post_commit_header_info = NULL;
- apr_status_t status;
serr = svn_fs_revision_root(&root, repos->fs, new_rev, pool);
if (serr != NULL)
@@ -235,13 +232,14 @@ dav_svn__merge_response(ap_filter_t *output,
repos->pool);
}
- bb = apr_brigade_create(pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(pool,
+ dav_svn__output_get_bucket_alloc(output));
/* prep some strings */
/* the HREF for the baseline is actually the VCC */
vcc = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_VCC, SVN_IGNORED_REVNUM,
- NULL, 0 /* add_href */, pool);
+ NULL, FALSE /* add_href */, pool);
/* the version-name of the baseline is the revision number */
rev = apr_psprintf(pool, "%ld", new_rev);
@@ -285,7 +283,7 @@ dav_svn__merge_response(ap_filter_t *output,
}
- status = ap_fputstrs(output, bb,
+ serr = dav_svn__brigade_putstrs(bb, output,
DAV_XML_HEADER DEBUG_CR
"<D:merge-response xmlns:D=\"DAV:\"",
post_commit_header_info,
@@ -304,44 +302,47 @@ dav_svn__merge_response(ap_filter_t *output,
"<D:resourcetype><D:baseline/></D:resourcetype>" DEBUG_CR,
post_commit_err_elem, DEBUG_CR
"<D:version-name>", rev, "</D:version-name>" DEBUG_CR,
- NULL);
- if (status != APR_SUCCESS)
- return dav_svn__new_error(repos->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write output");
+ SVN_VA_NULL);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write output",
+ repos->pool);
if (creationdate)
{
- status = ap_fputstrs(output, bb,
+ serr = dav_svn__brigade_putstrs(bb, output,
"<D:creationdate>",
apr_xml_quote_string(pool, creationdate->data, 1),
"</D:creationdate>" DEBUG_CR,
- NULL);
- if (status != APR_SUCCESS)
- return dav_svn__new_error(repos->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write output");
+ SVN_VA_NULL);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write output",
+ repos->pool);
}
if (creator_displayname)
{
- status = ap_fputstrs(output, bb,
+ serr = dav_svn__brigade_putstrs(bb, output,
"<D:creator-displayname>",
apr_xml_quote_string(pool,
creator_displayname->data, 1),
"</D:creator-displayname>" DEBUG_CR,
- NULL);
- if (status != APR_SUCCESS)
- return dav_svn__new_error(repos->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write output");
+ SVN_VA_NULL);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write output",
+ repos->pool);
}
- status = ap_fputstrs(output, bb,
+ serr = dav_svn__brigade_putstrs(bb, output,
"</D:prop>" DEBUG_CR
"<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
"</D:propstat>" DEBUG_CR
"</D:response>" DEBUG_CR,
-
- NULL);
- if (status != APR_SUCCESS)
- return dav_svn__new_error(repos->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write output");
+ SVN_VA_NULL);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write output",
+ repos->pool);
/* ONLY have dir_delta drive the editor if the caller asked us to
generate a full MERGE response. svn clients can ask us to
@@ -370,18 +371,20 @@ dav_svn__merge_response(ap_filter_t *output,
}
/* wrap up the merge response */
- status = ap_fputs(output, bb,
- "</D:updated-set>" DEBUG_CR
- "</D:merge-response>" DEBUG_CR);
- if (status != APR_SUCCESS)
- return dav_svn__new_error(repos->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write output");
+ serr = dav_svn__brigade_puts(bb, output,
+ "</D:updated-set>" DEBUG_CR
+ "</D:merge-response>" DEBUG_CR);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write output",
+ repos->pool);
/* send whatever is left in the brigade */
- status = ap_pass_brigade(output, bb);
- if (status != APR_SUCCESS)
- return dav_svn__new_error(repos->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write output");
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write output",
+ repos->pool);
return NULL;
}
diff --git a/subversion/mod_dav_svn/mirror.c b/subversion/mod_dav_svn/mirror.c
index e8b19a8..5b0f1f5 100644
--- a/subversion/mod_dav_svn/mirror.c
+++ b/subversion/mod_dav_svn/mirror.c
@@ -56,7 +56,7 @@ static int proxy_request_fixup(request_rec *r,
r->filename = (char *) svn_path_uri_encode(apr_pstrcat(r->pool, "proxy:",
master_uri,
uri_segment,
- (char *)NULL),
+ SVN_VA_NULL),
r->pool);
r->handler = "proxy-server";
@@ -102,11 +102,11 @@ int dav_svn__proxy_request_fixup(request_rec *r)
r->method_number == M_GET) {
if ((seg = ap_strstr(r->uri, root_dir))) {
if (ap_strstr_c(seg, apr_pstrcat(r->pool, special_uri,
- "/wrk/", (char *)NULL))
+ "/wrk/", SVN_VA_NULL))
|| ap_strstr_c(seg, apr_pstrcat(r->pool, special_uri,
- "/txn/", (char *)NULL))
+ "/txn/", SVN_VA_NULL))
|| ap_strstr_c(seg, apr_pstrcat(r->pool, special_uri,
- "/txr/", (char *)NULL))) {
+ "/txr/", SVN_VA_NULL))) {
int rv;
seg += strlen(root_dir);
rv = proxy_request_fixup(r, master_uri, seg);
@@ -259,7 +259,7 @@ apr_status_t dav_svn__location_header_filter(ap_filter_t *f,
new_uri = ap_construct_url(r->pool,
apr_pstrcat(r->pool,
dav_svn__get_root_dir(r), "/",
- start_foo, (char *)NULL),
+ start_foo, SVN_VA_NULL),
r);
apr_table_set(r->headers_out, "Location", new_uri);
}
diff --git a/subversion/mod_dav_svn/mod_dav_svn.c b/subversion/mod_dav_svn/mod_dav_svn.c
index a97d307..a6988fd 100644
--- a/subversion/mod_dav_svn/mod_dav_svn.c
+++ b/subversion/mod_dav_svn/mod_dav_svn.c
@@ -72,7 +72,7 @@ typedef struct server_conf_t {
/* A tri-state enum used for per directory on/off flags. Note that
it's important that CONF_FLAG_DEFAULT is 0 to make
- dav_svn_merge_dir_config do the right thing. */
+ merge_dir_config in mod_dav_svn do the right thing. */
enum conf_flag {
CONF_FLAG_DEFAULT,
CONF_FLAG_ON,
@@ -105,6 +105,7 @@ typedef struct dir_conf_t {
enum conf_flag txdelta_cache; /* whether to enable txdelta caching */
enum conf_flag fulltext_cache; /* whether to enable fulltext caching */
enum conf_flag revprop_cache; /* whether to enable revprop caching */
+ enum conf_flag block_read; /* whether to enable block read mode */
const char *hooks_env; /* path to hook script env config file */
} dir_conf_t;
@@ -142,6 +143,25 @@ init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
return OK;
}
+static svn_error_t *
+malfunction_handler(svn_boolean_t can_return,
+ const char *file, int line,
+ const char *expr)
+{
+ if (expr)
+ ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
+ "mod_dav_svn: file '%s', line %d, assertion \"%s\" failed",
+ file, line, expr);
+ else
+ ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
+ "mod_dav_svn: file '%s', line %d, internal malfunction",
+ file, line);
+ abort();
+
+ /* Should not be reached. */
+ return SVN_NO_ERROR;
+}
+
static int
init_dso(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
{
@@ -161,6 +181,8 @@ init_dso(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
return HTTP_INTERNAL_SERVER_ERROR;
}
+ svn_error_set_malfunction_handler(malfunction_handler);
+
return OK;
}
@@ -215,8 +237,9 @@ create_dir_config(apr_pool_t *p, char *dir)
if (dir)
conf->root_dir = svn_urlpath__canonicalize(dir, p);
conf->bulk_updates = CONF_BULKUPD_DEFAULT;
- conf->v2_protocol = CONF_FLAG_ON;
+ conf->v2_protocol = CONF_FLAG_DEFAULT;
conf->hooks_env = NULL;
+ conf->txdelta_cache = CONF_FLAG_DEFAULT;
return conf;
}
@@ -247,6 +270,7 @@ merge_dir_config(apr_pool_t *p, void *base, void *overrides)
newconf->txdelta_cache = INHERIT_VALUE(parent, child, txdelta_cache);
newconf->fulltext_cache = INHERIT_VALUE(parent, child, fulltext_cache);
newconf->revprop_cache = INHERIT_VALUE(parent, child, revprop_cache);
+ newconf->block_read = INHERIT_VALUE(parent, child, block_read);
newconf->root_dir = INHERIT_VALUE(parent, child, root_dir);
newconf->hooks_env = INHERIT_VALUE(parent, child, hooks_env);
@@ -543,6 +567,19 @@ SVNCacheRevProps_cmd(cmd_parms *cmd, void *config, int arg)
}
static const char *
+SVNBlockRead_cmd(cmd_parms *cmd, void *config, int arg)
+{
+ dir_conf_t *conf = config;
+
+ if (arg)
+ conf->block_read = CONF_FLAG_ON;
+ else
+ conf->block_read = CONF_FLAG_OFF;
+
+ return NULL;
+}
+
+static const char *
SVNInMemoryCacheSize_cmd(cmd_parms *cmd, void *config, const char *arg1)
{
svn_cache_config_t settings = *svn_cache_config_get();
@@ -612,6 +649,16 @@ SVNHooksEnv_cmd(cmd_parms *cmd, void *config, const char *arg1)
return NULL;
}
+static svn_boolean_t
+get_conf_flag(enum conf_flag flag, svn_boolean_t default_value)
+{
+ if (flag == CONF_FLAG_ON)
+ return TRUE;
+ else if (flag == CONF_FLAG_OFF)
+ return FALSE;
+ else /* CONF_FLAG_DEFAULT*/
+ return default_value;
+}
/** Accessor functions for the module's configuration state **/
@@ -636,9 +683,10 @@ dav_svn__get_fs_parent_path(request_rec *r)
AP_MODULE_DECLARE(dav_error *)
-dav_svn_get_repos_path(request_rec *r,
- const char *root_path,
- const char **repos_path)
+dav_svn_get_repos_path2(request_rec *r,
+ const char *root_path,
+ const char **repos_path,
+ apr_pool_t *pool)
{
const char *fs_path;
@@ -666,19 +714,26 @@ dav_svn_get_repos_path(request_rec *r,
/* Split the svn URI to get the name of the repository below
the parent path. */
- derr = dav_svn_split_uri(r, r->uri, root_path,
- &ignored_cleaned_uri, &ignored_had_slash,
- &repos_name,
- &ignored_relative, &ignored_path_in_repos);
+ derr = dav_svn_split_uri2(r, r->uri, root_path,
+ &ignored_cleaned_uri, &ignored_had_slash,
+ &repos_name,
+ &ignored_relative, &ignored_path_in_repos, pool);
if (derr)
return derr;
/* Construct the full path from the parent path base directory
and the repository name. */
- *repos_path = svn_dirent_join(fs_parent_path, repos_name, r->pool);
+ *repos_path = svn_dirent_join(fs_parent_path, repos_name, pool);
return NULL;
}
+AP_MODULE_DECLARE(dav_error *)
+dav_svn_get_repos_path(request_rec *r,
+ const char *root_path,
+ const char **repos_path)
+{
+ return dav_svn_get_repos_path2(r, root_path, repos_path, r->pool);
+}
const char *
dav_svn__get_repo_name(request_rec *r)
@@ -745,7 +800,7 @@ const char *
dav_svn__get_me_resource_uri(request_rec *r)
{
return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/me",
- (char *)NULL);
+ SVN_VA_NULL);
}
@@ -753,7 +808,7 @@ const char *
dav_svn__get_rev_stub(request_rec *r)
{
return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/rev",
- (char *)NULL);
+ SVN_VA_NULL);
}
@@ -761,7 +816,7 @@ const char *
dav_svn__get_rev_root_stub(request_rec *r)
{
return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/rvr",
- (char *)NULL);
+ SVN_VA_NULL);
}
@@ -769,14 +824,14 @@ const char *
dav_svn__get_txn_stub(request_rec *r)
{
return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/txn",
- (char *)NULL);
+ SVN_VA_NULL);
}
const char *
dav_svn__get_txn_root_stub(request_rec *r)
{
- return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/txr", (char *)NULL);
+ return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/txr", SVN_VA_NULL);
}
@@ -784,7 +839,7 @@ const char *
dav_svn__get_vtxn_stub(request_rec *r)
{
return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/vtxn",
- (char *)NULL);
+ SVN_VA_NULL);
}
@@ -792,7 +847,7 @@ const char *
dav_svn__get_vtxn_root_stub(request_rec *r)
{
return apr_pstrcat(r->pool, dav_svn__get_special_uri(r), "/vtxr",
- (char *)NULL);
+ SVN_VA_NULL);
}
@@ -828,7 +883,7 @@ dav_svn__check_httpv2_support(request_rec *r)
svn_boolean_t available;
conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
- available = conf->v2_protocol == CONF_FLAG_ON;
+ available = get_conf_flag(conf->v2_protocol, TRUE);
/* If our configuration says that HTTPv2 is available, but we are
proxying requests to a master Subversion server which lacks
@@ -911,7 +966,9 @@ dav_svn__get_txdelta_cache_flag(request_rec *r)
dir_conf_t *conf;
conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
- return conf->txdelta_cache == CONF_FLAG_ON;
+
+ /* txdelta caching is enabled by default. */
+ return get_conf_flag(conf->txdelta_cache, TRUE);
}
@@ -935,6 +992,15 @@ dav_svn__get_revprop_cache_flag(request_rec *r)
}
+svn_boolean_t
+dav_svn__get_block_read_flag(request_rec *r)
+{
+ dir_conf_t *conf;
+
+ conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
+ return conf->block_read == CONF_FLAG_ON;
+}
+
int
dav_svn__get_compression_level(request_rec *r)
{
@@ -984,7 +1050,6 @@ merge_xml_filter_insert(request_rec *r)
typedef struct merge_ctx_t {
apr_bucket_brigade *bb;
apr_xml_parser *parser;
- apr_pool_t *pool;
} merge_ctx_t;
@@ -1014,7 +1079,6 @@ merge_xml_in_filter(ap_filter_t *f,
f->ctx = ctx = apr_palloc(r->pool, sizeof(*ctx));
ctx->parser = apr_xml_parser_create(r->pool);
ctx->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
- apr_pool_create(&ctx->pool, r->pool);
}
rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes);
@@ -1103,10 +1167,11 @@ static int dav_svn__handler(request_rec *r)
/* Fill the filename on the request with a bogus path since we aren't serving
* a file off the disk. This means that <Directory> blocks will not match and
- * that %f in logging formats will show as "svn:/path/to/repo/path/in/repo". */
+ * %f in logging formats will show as "dav_svn:/path/to/repo/path/in/repo".
+ */
static int dav_svn__translate_name(request_rec *r)
{
- const char *fs_path, *repos_basename, *repos_path, *slash;
+ const char *fs_path, *repos_basename, *repos_path;
const char *ignore_cleaned_uri, *ignore_relative_path;
int ignore_had_slash;
dir_conf_t *conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
@@ -1148,19 +1213,11 @@ static int dav_svn__translate_name(request_rec *r)
fs_path = conf->fs_path;
}
- /* Avoid a trailing slash on the bogus path when repos_path is just "/" and
- * ensure that there is always a slash between fs_path and repos_path as
- * long as the repos_path is not an empty path. */
- slash = "";
- if (repos_path)
- {
- if ('/' == repos_path[0] && '\0' == repos_path[1])
- repos_path = NULL;
- else if ('/' != repos_path[0] && '\0' != repos_path[0])
- slash = "/";
- }
+ /* Avoid a trailing slash on the bogus path when repos_path is just "/" */
+ if (repos_path && '/' == repos_path[0] && '\0' == repos_path[1])
+ repos_path = NULL;
- /* Combine 'svn:', fs_path and repos_path to produce the bogus path we're
+ /* Combine 'dav_svn:', fs_path and repos_path to produce the bogus path we're
* placing in r->filename. We can't use our standard join helpers such
* as svn_dirent_join. fs_path is a dirent and repos_path is a fspath
* (that can be trivially converted to a relpath by skipping the leading
@@ -1168,7 +1225,7 @@ static int dav_svn__translate_name(request_rec *r)
* repository is 'trunk/c:hi' this results in a non canonical dirent on
* Windows. Instead we just cat them together. */
r->filename = apr_pstrcat(r->pool,
- "svn:", fs_path, slash, repos_path, NULL);
+ "dav_svn:", fs_path, repos_path, SVN_VA_NULL);
/* Leave a note to ourselves so that we know not to decline in the
* map_to_storage hook. */
@@ -1268,7 +1325,7 @@ static const command_rec cmds[] =
ACCESS_CONF|RSRC_CONF,
"speeds up data access to older revisions by caching "
"delta information if sufficient in-memory cache is "
- "available (default is Off)."),
+ "available (default is On)."),
/* per directory/location */
AP_INIT_FLAG("SVNCacheFullTexts", SVNCacheFullTexts_cmd, NULL,
@@ -1285,12 +1342,19 @@ static const command_rec cmds[] =
"in the documentation"
"(default is Off)."),
+ /* per directory/location */
+ AP_INIT_FLAG("SVNBlockRead", SVNBlockRead_cmd, NULL,
+ ACCESS_CONF|RSRC_CONF,
+ "speeds up operations of FSFS 1.9+ repositories if large"
+ "caches (see SVNInMemoryCacheSize) have been configured."
+ "(default is Off)."),
+
/* per server */
AP_INIT_TAKE1("SVNInMemoryCacheSize", SVNInMemoryCacheSize_cmd, NULL,
RSRC_CONF,
"specifies the maximum size in kB per process of Subversion's "
- "in-memory object cache (default value is 16384; 0 deactivates "
- "the cache)."),
+ "in-memory object cache (default value is 16384; 0 switches "
+ "to dynamically sized caches)."),
/* per server */
AP_INIT_TAKE1("SVNCompressionLevel", SVNCompressionLevel_cmd, NULL,
RSRC_CONF,
@@ -1345,6 +1409,9 @@ register_hooks(apr_pool_t *pconf)
/* general request handler for methods which mod_dav DECLINEs. */
ap_hook_handler(dav_svn__handler, NULL, NULL, APR_HOOK_LAST);
+ /* Handler to GET Subversion's FSFS cache stats, a bit like mod_status. */
+ ap_hook_handler(dav_svn__status, NULL, NULL, APR_HOOK_MIDDLE);
+
/* live property handling */
dav_hook_gather_propsets(dav_svn__gather_propsets, NULL, NULL,
APR_HOOK_MIDDLE);
diff --git a/subversion/mod_dav_svn/posts/create_txn.c b/subversion/mod_dav_svn/posts/create_txn.c
index 4775749..b5e4e99 100644
--- a/subversion/mod_dav_svn/posts/create_txn.c
+++ b/subversion/mod_dav_svn/posts/create_txn.c
@@ -34,7 +34,7 @@
dav_error *
dav_svn__post_create_txn(const dav_resource *resource,
svn_skel_t *request_skel,
- ap_filter_t *output)
+ dav_svn__output *output)
{
const char *txn_name;
const char *vtxn_name;
@@ -75,7 +75,7 @@ dav_svn__post_create_txn(const dav_resource *resource,
dav_error *
dav_svn__post_create_txn_with_props(const dav_resource *resource,
svn_skel_t *request_skel,
- ap_filter_t *output)
+ dav_svn__output *output)
{
const char *txn_name;
const char *vtxn_name;
diff --git a/subversion/mod_dav_svn/reports/dated-rev.c b/subversion/mod_dav_svn/reports/dated-rev.c
index 61d26f5..5ba607b 100644
--- a/subversion/mod_dav_svn/reports/dated-rev.c
+++ b/subversion/mod_dav_svn/reports/dated-rev.c
@@ -50,7 +50,7 @@
dav_error *
dav_svn__dated_rev_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
apr_xml_elem *child;
int ns;
@@ -58,7 +58,6 @@ dav_svn__dated_rev_report(const dav_resource *resource,
svn_revnum_t rev;
apr_bucket_brigade *bb;
svn_error_t *err;
- apr_status_t apr_err;
dav_error *derr = NULL;
/* Find the DAV:creationdate element and get the requested time from it. */
@@ -94,15 +93,16 @@ dav_svn__dated_rev_report(const dav_resource *resource,
"Could not access revision times.");
}
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
- apr_err = ap_fprintf(output, bb,
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
+ err = dav_svn__brigade_printf(bb, output,
DAV_XML_HEADER DEBUG_CR
"<S:dated-rev-report xmlns:S=\"" SVN_XML_NAMESPACE "\" "
"xmlns:D=\"DAV:\">" DEBUG_CR
"<D:" SVN_DAV__VERSION_NAME ">%ld</D:"
SVN_DAV__VERSION_NAME ">""</S:dated-rev-report>", rev);
- if (apr_err)
- derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL),
+ if (err)
+ derr = dav_svn__convert_err(err,
HTTP_INTERNAL_SERVER_ERROR,
"Error writing REPORT response.",
resource->pool);
diff --git a/subversion/mod_dav_svn/reports/deleted-rev.c b/subversion/mod_dav_svn/reports/deleted-rev.c
index 66d0192..a21aaec 100644
--- a/subversion/mod_dav_svn/reports/deleted-rev.c
+++ b/subversion/mod_dav_svn/reports/deleted-rev.c
@@ -41,7 +41,7 @@
dav_error *
dav_svn__get_deleted_rev_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
apr_xml_elem *child;
int ns;
@@ -52,7 +52,6 @@ dav_svn__get_deleted_rev_report(const dav_resource *resource,
svn_revnum_t deleted_rev;
apr_bucket_brigade *bb;
svn_error_t *err;
- apr_status_t apr_err;
dav_error *derr = NULL;
/* Sanity check. */
@@ -61,12 +60,10 @@ dav_svn__get_deleted_rev_report(const dav_resource *resource,
"The request does not specify a repository path");
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
for (child = doc->root->first_child; child != NULL; child = child->next)
{
@@ -104,10 +101,8 @@ dav_svn__get_deleted_rev_report(const dav_resource *resource,
&& SVN_IS_VALID_REVNUM(peg_rev)
&& SVN_IS_VALID_REVNUM(end_rev)))
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
- "Not all parameters passed.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
+ "Not all parameters passed");
}
/* Do what we actually came here for: Find the rev abs_path was deleted. */
@@ -121,16 +116,17 @@ dav_svn__get_deleted_rev_report(const dav_resource *resource,
"Could not find revision path was deleted.");
}
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
- apr_err = ap_fprintf(output, bb,
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
+ err = dav_svn__brigade_printf(bb, output,
DAV_XML_HEADER DEBUG_CR
"<S:get-deleted-rev-report xmlns:S=\""
SVN_XML_NAMESPACE "\" xmlns:D=\"DAV:\">" DEBUG_CR
"<D:" SVN_DAV__VERSION_NAME ">%ld</D:"
SVN_DAV__VERSION_NAME ">""</S:get-deleted-rev-report>",
deleted_rev);
- if (apr_err)
- derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL),
+ if (err)
+ derr = dav_svn__convert_err(err,
HTTP_INTERNAL_SERVER_ERROR,
"Error writing REPORT response.",
resource->pool);
diff --git a/subversion/mod_dav_svn/reports/file-revs.c b/subversion/mod_dav_svn/reports/file-revs.c
index 108fd7f..5392776 100644
--- a/subversion/mod_dav_svn/reports/file-revs.c
+++ b/subversion/mod_dav_svn/reports/file-revs.c
@@ -43,7 +43,7 @@ struct file_rev_baton {
apr_bucket_brigade *bb;
/* where to deliver the output */
- ap_filter_t *output;
+ dav_svn__output *output;
/* Whether we've written the <S:file-revs-report> header. Allows for lazy
writes to support mod_dav-based error handling. */
@@ -149,7 +149,7 @@ file_rev_handler(void *baton,
apr_pool_t *pool)
{
struct file_rev_baton *frb = baton;
- apr_pool_t *subpool = svn_pool_create(pool);
+ apr_pool_t *iterpool = svn_pool_create(pool);
apr_hash_index_t *hi;
int i;
@@ -169,11 +169,11 @@ file_rev_handler(void *baton,
const char *pname;
const svn_string_t *pval;
- svn_pool_clear(subpool);
+ svn_pool_clear(iterpool);
apr_hash_this(hi, &key, NULL, &val);
pname = key;
pval = val;
- SVN_ERR(send_prop(frb, "rev-prop", pname, pval, subpool));
+ SVN_ERR(send_prop(frb, "rev-prop", pname, pval, iterpool));
}
/* Send file prop changes. */
@@ -181,17 +181,17 @@ file_rev_handler(void *baton,
{
const svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
- svn_pool_clear(subpool);
+ svn_pool_clear(iterpool);
if (prop->value)
SVN_ERR(send_prop(frb, "set-prop", prop->name, prop->value,
- subpool));
+ iterpool));
else
{
/* Property was removed. */
SVN_ERR(dav_svn__brigade_printf(frb->bb, frb->output,
"<S:remove-prop name=\"%s\"/>"
DEBUG_CR,
- apr_xml_quote_string(subpool,
+ apr_xml_quote_string(iterpool,
prop->name,
1)));
}
@@ -223,7 +223,7 @@ file_rev_handler(void *baton,
SVN_ERR(dav_svn__brigade_puts(frb->bb, frb->output,
"</S:file-rev>" DEBUG_CR));
- svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -234,7 +234,7 @@ file_rev_handler(void *baton,
dav_error *
dav_svn__file_revs_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
@@ -262,12 +262,10 @@ dav_svn__file_revs_report(const dav_resource *resource,
in this namespace, so is this necessary at all? */
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
/* Get request information. */
@@ -302,13 +300,11 @@ dav_svn__file_revs_report(const dav_resource *resource,
/* Check that all parameters are present and valid. */
if (! abs_path)
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
- "Not all parameters passed.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
+ "Not all parameters passed");
frb.bb = apr_brigade_create(resource->pool,
- output->c->bucket_alloc);
+ dav_svn__output_get_bucket_alloc(output));
frb.output = output;
frb.needs_header = TRUE;
frb.svndiff_version = resource->info->svndiff_version;
@@ -331,7 +327,7 @@ dav_svn__file_revs_report(const dav_resource *resource,
right then, so r->status remains 0, hence HTTP status 200
would be misleadingly returned. */
return (dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
- serr->message, resource->pool));
+ NULL, resource->pool));
}
if ((serr = maybe_send_header(&frb)))
diff --git a/subversion/mod_dav_svn/reports/get-location-segments.c b/subversion/mod_dav_svn/reports/get-location-segments.c
index d3e91e4..794e27f 100644
--- a/subversion/mod_dav_svn/reports/get-location-segments.c
+++ b/subversion/mod_dav_svn/reports/get-location-segments.c
@@ -48,7 +48,7 @@
struct location_segment_baton
{
svn_boolean_t sent_opener;
- ap_filter_t *output;
+ dav_svn__output *output;
apr_bucket_brigade *bb;
dav_svn__authz_read_baton arb;
};
@@ -79,28 +79,26 @@ location_segment_receiver(svn_location_segment_t *segment,
apr_pool_t *pool)
{
struct location_segment_baton *b = baton;
- apr_status_t apr_err;
SVN_ERR(maybe_send_opener(b));
if (segment->path)
{
const char *path_quoted = apr_xml_quote_string(pool, segment->path, 1);
- apr_err = ap_fprintf(b->output, b->bb,
+
+ SVN_ERR(dav_svn__brigade_printf(b->bb, b->output,
"<S:location-segment path=\"%s\" "
"range-start=\"%ld\" range-end=\"%ld\"/>" DEBUG_CR,
path_quoted,
- segment->range_start, segment->range_end);
+ segment->range_start, segment->range_end));
}
else
{
- apr_err = ap_fprintf(b->output, b->bb,
+ SVN_ERR(dav_svn__brigade_printf(b->bb, b->output,
"<S:location-segment "
"range-start=\"%ld\" range-end=\"%ld\"/>" DEBUG_CR,
- segment->range_start, segment->range_end);
+ segment->range_start, segment->range_end));
}
- if (apr_err)
- return svn_error_create(apr_err, 0, NULL);
return SVN_NO_ERROR;
}
@@ -108,7 +106,7 @@ location_segment_receiver(svn_location_segment_t *segment,
dav_error *
dav_svn__get_location_segments_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
@@ -129,12 +127,10 @@ dav_svn__get_location_segments_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
/* Gather the parameters. */
@@ -177,10 +173,8 @@ dav_svn__get_location_segments_report(const dav_resource *resource,
/* Check that all parameters are present and valid. */
if (! abs_path)
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
- "Not all parameters passed.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
+ "Not all parameters passed");
/* No START_REV or PEG_REVISION? We'll use HEAD. */
if (!SVN_IS_VALID_REVNUM(start_rev) || !SVN_IS_VALID_REVNUM(peg_revision))
@@ -205,24 +199,21 @@ dav_svn__get_location_segments_report(const dav_resource *resource,
end_rev = 0;
if (end_rev > start_rev)
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"End revision must not be younger than "
- "start revision",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "start revision");
if (start_rev > peg_revision)
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"Start revision must not be younger than "
- "peg revision",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "peg revision");
/* Build an authz read baton. */
arb.r = resource->info->r;
arb.repos = resource->info->repos;
/* Build the bucket brigade we'll use for output. */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
/* Do what we came here for. */
location_segment_baton.sent_opener = FALSE;
@@ -236,7 +227,7 @@ dav_svn__get_location_segments_report(const dav_resource *resource,
dav_svn__authz_read_func(&arb),
&arb, resource->pool)))
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
diff --git a/subversion/mod_dav_svn/reports/get-locations.c b/subversion/mod_dav_svn/reports/get-locations.c
index 164045f..da70300 100644
--- a/subversion/mod_dav_svn/reports/get-locations.c
+++ b/subversion/mod_dav_svn/reports/get-locations.c
@@ -44,23 +44,20 @@
#include "../dav_svn.h"
-static apr_status_t
-send_get_locations_report(ap_filter_t *output,
+static svn_error_t *
+send_get_locations_report(dav_svn__output *output,
apr_bucket_brigade *bb,
const dav_resource *resource,
apr_hash_t *fs_locations)
{
apr_hash_index_t *hi;
- apr_pool_t *pool;
- apr_status_t apr_err;
+ apr_pool_t *pool = resource->pool;
- pool = resource->pool;
-
- apr_err = ap_fprintf(output, bb, DAV_XML_HEADER DEBUG_CR
+ SVN_ERR(dav_svn__brigade_printf(
+ bb, output,
+ DAV_XML_HEADER DEBUG_CR
"<S:get-locations-report xmlns:S=\"" SVN_XML_NAMESPACE
- "\" xmlns:D=\"DAV:\">" DEBUG_CR);
- if (apr_err)
- return apr_err;
+ "\" xmlns:D=\"DAV:\">" DEBUG_CR));
for (hi = apr_hash_first(pool, fs_locations); hi; hi = apr_hash_next(hi))
{
@@ -70,24 +67,25 @@ send_get_locations_report(ap_filter_t *output,
apr_hash_this(hi, &key, NULL, &value);
path_quoted = apr_xml_quote_string(pool, value, 1);
- apr_err = ap_fprintf(output, bb, "<S:location "
+ SVN_ERR(dav_svn__brigade_printf(
+ bb, output, "<S:location "
"rev=\"%ld\" path=\"%s\"/>" DEBUG_CR,
- *(const svn_revnum_t *)key, path_quoted);
- if (apr_err)
- return apr_err;
+ *(const svn_revnum_t *)key, path_quoted));
}
- return ap_fprintf(output, bb, "</S:get-locations-report>" DEBUG_CR);
+
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ "</S:get-locations-report>" DEBUG_CR));
+ return SVN_NO_ERROR;
}
dav_error *
dav_svn__get_locations_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
- apr_status_t apr_err;
apr_bucket_brigade *bb;
dav_svn__authz_read_baton arb;
@@ -112,12 +110,10 @@ dav_svn__get_locations_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
/* Gather the parameters. */
@@ -154,10 +150,8 @@ dav_svn__get_locations_report(const dav_resource *resource,
/* Check that all parameters are present and valid. */
if (! (abs_path && SVN_IS_VALID_REVNUM(peg_revision)))
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
- "Not all parameters passed.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
+ "Not all parameters passed");
/* Build an authz read baton */
arb.r = resource->info->r;
@@ -171,16 +165,17 @@ dav_svn__get_locations_report(const dav_resource *resource,
if (serr)
{
- return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
- serr->message, resource->pool);
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, NULL,
+ resource->pool);
}
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
- apr_err = send_get_locations_report(output, bb, resource, fs_locations);
+ serr = send_get_locations_report(output, bb, resource, fs_locations);
- if (apr_err)
- derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL),
+ if (serr)
+ derr = dav_svn__convert_err(serr,
HTTP_INTERNAL_SERVER_ERROR,
"Error writing REPORT response.",
resource->pool);
diff --git a/subversion/mod_dav_svn/reports/get-locks.c b/subversion/mod_dav_svn/reports/get-locks.c
index 06fd700..bb9c168 100644
--- a/subversion/mod_dav_svn/reports/get-locks.c
+++ b/subversion/mod_dav_svn/reports/get-locks.c
@@ -44,67 +44,51 @@
report in libsvn_ra_neon/get_locks.c. */
-#define SVN_APR_ERR(expr) \
- do { \
- apr_status_t apr_status__temp = (expr); \
- if (apr_status__temp) \
- return apr_status__temp; \
- } while (0)
-
-
/* Transmit LOCKS (a hash of Subversion filesystem locks keyed by
- path) across OUTPUT using BB. Use POOL for necessary allocations.
-
- NOTE: As written, this function currently returns one of only two
- status values -- "success", and "we had trouble writing out to the
- output stream". If you need to return something more interesting,
- you'll probably want to generate dav_error's here instead of
- passing back only apr_status_t's. */
-static apr_status_t
+ path) across OUTPUT using BB. Use POOL for necessary allocations. */
+static svn_error_t *
send_get_lock_response(apr_hash_t *locks,
- ap_filter_t *output,
+ dav_svn__output *output,
apr_bucket_brigade *bb,
apr_pool_t *pool)
{
- apr_pool_t *subpool;
+ apr_pool_t *iterpool;
apr_hash_index_t *hi;
/* start sending report */
- SVN_APR_ERR(ap_fprintf(output, bb,
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
DAV_XML_HEADER DEBUG_CR
"<S:get-locks-report xmlns:S=\"" SVN_XML_NAMESPACE
"\" xmlns:D=\"DAV:\">" DEBUG_CR));
/* stream the locks */
- subpool = svn_pool_create(pool);
+ iterpool = svn_pool_create(pool);
for (hi = apr_hash_first(pool, locks); hi; hi = apr_hash_next(hi))
{
- void *val;
const svn_lock_t *lock;
- svn_pool_clear(subpool);
- apr_hash_this(hi, NULL, NULL, &val);
- lock = val;
+ svn_pool_clear(iterpool);
+ lock = apr_hash_this_val(hi);
/* Begin the <S:lock> tag, transmitting the path, token, and
creation date. */
- SVN_APR_ERR(ap_fprintf(output, bb,
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
"<S:lock>" DEBUG_CR
"<S:path>%s</S:path>" DEBUG_CR
"<S:token>%s</S:token>" DEBUG_CR
"<S:creationdate>%s</S:creationdate>" DEBUG_CR,
- apr_xml_quote_string(subpool, lock->path, 1),
- apr_xml_quote_string(subpool, lock->token, 1),
+ apr_xml_quote_string(iterpool, lock->path, 1),
+ apr_xml_quote_string(iterpool, lock->token, 1),
svn_time_to_cstring(lock->creation_date,
- subpool)));
+ iterpool)));
/* Got expiration date? Tell the client. */
if (lock->expiration_date)
- SVN_APR_ERR(ap_fprintf(output, bb,
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
"<S:expirationdate>%s</S:expirationdate>"
DEBUG_CR,
svn_time_to_cstring(lock->expiration_date,
- subpool)));
+ iterpool)));
/* Transmit the lock ownership information. */
if (lock->owner)
@@ -114,7 +98,7 @@ send_get_lock_response(apr_hash_t *locks,
if (svn_xml_is_xml_safe(lock->owner, strlen(lock->owner)))
{
- owner = apr_xml_quote_string(subpool, lock->owner, 1);
+ owner = apr_xml_quote_string(iterpool, lock->owner, 1);
}
else
{
@@ -124,11 +108,11 @@ send_get_lock_response(apr_hash_t *locks,
owner_string.data = lock->owner;
owner_string.len = strlen(lock->owner);
encoded_owner = svn_base64_encode_string2(&owner_string, TRUE,
- subpool);
+ iterpool);
owner = encoded_owner->data;
owner_base64 = TRUE;
}
- SVN_APR_ERR(ap_fprintf(output, bb,
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
"<S:owner %s>%s</S:owner>" DEBUG_CR,
owner_base64 ? "encoding=\"base64\"" : "",
owner));
@@ -142,7 +126,7 @@ send_get_lock_response(apr_hash_t *locks,
if (svn_xml_is_xml_safe(lock->comment, strlen(lock->comment)))
{
- comment = apr_xml_quote_string(subpool, lock->comment, 1);
+ comment = apr_xml_quote_string(iterpool, lock->comment, 1);
}
else
{
@@ -152,38 +136,36 @@ send_get_lock_response(apr_hash_t *locks,
comment_string.data = lock->comment;
comment_string.len = strlen(lock->comment);
encoded_comment = svn_base64_encode_string2(&comment_string,
- TRUE, subpool);
+ TRUE, iterpool);
comment = encoded_comment->data;
comment_base64 = TRUE;
}
- SVN_APR_ERR(ap_fprintf(output, bb,
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
"<S:comment %s>%s</S:comment>" DEBUG_CR,
comment_base64 ? "encoding=\"base64\"" : "",
comment));
}
/* Okay, finish up this lock by closing the <S:lock> tag. */
- SVN_APR_ERR(ap_fprintf(output, bb, "</S:lock>" DEBUG_CR));
+ SVN_ERR(dav_svn__brigade_printf(bb, output, "</S:lock>" DEBUG_CR));
}
- svn_pool_destroy(subpool);
+ svn_pool_destroy(iterpool);
/* Finish the report */
- SVN_APR_ERR(ap_fprintf(output, bb, "</S:get-locks-report>" DEBUG_CR));
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ "</S:get-locks-report>" DEBUG_CR));
return APR_SUCCESS;
}
-#undef SVN_APR_ERR
-
dav_error *
dav_svn__get_locks_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
apr_bucket_brigade *bb;
svn_error_t *err;
dav_error *derr = NULL;
- apr_status_t apr_err;
apr_hash_t *locks;
dav_svn__authz_read_baton arb;
svn_depth_t depth = svn_depth_unknown;
@@ -229,10 +211,12 @@ dav_svn__get_locks_report(const dav_resource *resource,
return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
err->message, resource->pool);
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
- if ((apr_err = send_get_lock_response(locks, output, bb, resource->pool)))
- derr = dav_svn__convert_err(svn_error_create(apr_err, 0, NULL),
+ err = send_get_lock_response(locks, output, bb, resource->pool);
+ if (err)
+ derr = dav_svn__convert_err(err,
HTTP_INTERNAL_SERVER_ERROR,
"Error writing REPORT response.",
resource->pool);
diff --git a/subversion/mod_dav_svn/reports/inherited-props.c b/subversion/mod_dav_svn/reports/inherited-props.c
index ce0f4de..bb2300f 100644
--- a/subversion/mod_dav_svn/reports/inherited-props.c
+++ b/subversion/mod_dav_svn/reports/inherited-props.c
@@ -47,7 +47,7 @@
dav_error *
dav_svn__get_inherited_props_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
@@ -69,12 +69,10 @@ dav_svn__get_inherited_props_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
iterpool = svn_pool_create(resource->pool);
@@ -107,7 +105,8 @@ dav_svn__get_inherited_props_report(const dav_resource *resource,
arb.repos = resource->info->repos;
/* Build inherited property brigade */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
serr = svn_fs_revision_root(&root, resource->info->repos->fs,
rev, resource->pool);
@@ -121,7 +120,7 @@ dav_svn__get_inherited_props_report(const dav_resource *resource,
&arb, resource->pool, iterpool);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
@@ -133,7 +132,7 @@ dav_svn__get_inherited_props_report(const dav_resource *resource,
"xmlns:D=\"DAV:\">" DEBUG_CR);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
@@ -161,8 +160,8 @@ dav_svn__get_inherited_props_report(const dav_resource *resource,
hi;
hi = apr_hash_next(hi))
{
- const char *propname = svn__apr_hash_index_key(hi);
- svn_string_t *propval = svn__apr_hash_index_val(hi);
+ const char *propname = apr_hash_this_key(hi);
+ svn_string_t *propval = apr_hash_this_val(hi);
const char *xml_safe;
serr = dav_svn__brigade_printf(
diff --git a/subversion/mod_dav_svn/reports/log.c b/subversion/mod_dav_svn/reports/log.c
index acd33ed..76a47c8 100644
--- a/subversion/mod_dav_svn/reports/log.c
+++ b/subversion/mod_dav_svn/reports/log.c
@@ -50,7 +50,7 @@ struct log_receiver_baton
apr_bucket_brigade *bb;
/* where to deliver the output */
- ap_filter_t *output;
+ dav_svn__output *output;
/* Whether we've written the <S:log-report> header. Allows for lazy
writes to support mod_dav-based error handling. */
@@ -65,6 +65,10 @@ struct log_receiver_baton
/* whether the client can handle encoded binary property values */
svn_boolean_t encode_binary_props;
+
+ /* Helper variables to force early bucket brigade flushes */
+ int result_count;
+ int next_forced_flush;
};
@@ -87,6 +91,43 @@ maybe_send_header(struct log_receiver_baton *lrb)
return SVN_NO_ERROR;
}
+/* Utility for log_receiver opening a new XML element in LRB's brigade
+ for LOG_ITEM and return the element's name in *ELEMENT. Use POOL for
+ temporary allocations.
+
+ Call this function for items that may have a copy-from */
+static svn_error_t *
+start_path_with_copy_from(const char **element,
+ struct log_receiver_baton *lrb,
+ svn_log_changed_path2_t *log_item,
+ apr_pool_t *pool)
+{
+ switch (log_item->action)
+ {
+ case 'A': *element = "S:added-path";
+ break;
+ case 'R': *element = "S:replaced-path";
+ break;
+ default: /* Caller, you did wrong! */
+ SVN_ERR_MALFUNCTION();
+ }
+
+ if (log_item->copyfrom_path
+ && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
+ SVN_ERR(dav_svn__brigade_printf
+ (lrb->bb, lrb->output,
+ "<%s copyfrom-path=\"%s\" copyfrom-rev=\"%ld\"",
+ *element,
+ apr_xml_quote_string(pool,
+ log_item->copyfrom_path,
+ 1), /* escape quotes */
+ log_item->copyfrom_rev));
+ else
+ SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output, "<%s", *element));
+
+ return SVN_NO_ERROR;
+}
+
/* This implements `svn_log_entry_receiver_t'.
BATON is a `struct log_receiver_baton *'. */
@@ -203,39 +244,9 @@ log_receiver(void *baton,
switch (log_item->action)
{
case 'A':
- if (log_item->copyfrom_path
- && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
- SVN_ERR(dav_svn__brigade_printf
- (lrb->bb, lrb->output,
- "<S:added-path copyfrom-path=\"%s\""
- " copyfrom-rev=\"%ld\"",
- apr_xml_quote_string(iterpool,
- log_item->copyfrom_path,
- 1), /* escape quotes */
- log_item->copyfrom_rev));
- else
- SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
- "<S:added-path"));
-
- close_element = "S:added-path";
- break;
-
case 'R':
- if (log_item->copyfrom_path
- && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
- SVN_ERR(dav_svn__brigade_printf
- (lrb->bb, lrb->output,
- "<S:replaced-path copyfrom-path=\"%s\""
- " copyfrom-rev=\"%ld\"",
- apr_xml_quote_string(iterpool,
- log_item->copyfrom_path,
- 1), /* escape quotes */
- log_item->copyfrom_rev));
- else
- SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
- "<S:replaced-path"));
-
- close_element = "S:replaced-path";
+ SVN_ERR(start_path_with_copy_from(&close_element, lrb,
+ log_item, iterpool));
break;
case 'D':
@@ -275,6 +286,33 @@ log_receiver(void *baton,
SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
"</S:log-item>" DEBUG_CR));
+ /* In general APR will flush the brigade every 8000 bytes through the filter
+ stack, but log items may not be generated that fast, especially in
+ combination with authz and busy servers. We now explictly flush after
+ log-item 4, 16, 64 and 256 to produce a few results fast.
+
+ This introduces 4 full flushes of our brigade and the installed output
+ filters at growing intervals and then falls back to the standard
+ buffering of 8000 bytes + whatever buffers are added in output filters. */
+ lrb->result_count++;
+ if (lrb->result_count == lrb->next_forced_flush)
+ {
+ apr_bucket *bkt;
+
+ /* Compared to using ap_filter_flush(), which we use in other place
+ this adds a flush frame before flushing the brigade, to make output
+ filters perform a flush as well */
+
+ /* No brigade empty check. We want output filters to flush anyway */
+ bkt = apr_bucket_flush_create(
+ dav_svn__output_get_bucket_alloc(lrb->output));
+ APR_BRIGADE_INSERT_TAIL(lrb->bb, bkt);
+ SVN_ERR(dav_svn__output_pass_brigade(lrb->output, lrb->bb));
+
+ if (lrb->result_count < 256)
+ lrb->next_forced_flush = lrb->next_forced_flush * 4;
+ }
+
return SVN_NO_ERROR;
}
@@ -282,7 +320,7 @@ log_receiver(void *baton,
dav_error *
dav_svn__log_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
@@ -301,6 +339,7 @@ dav_svn__log_report(const dav_resource *resource,
svn_boolean_t discover_changed_paths = FALSE; /* off by default */
svn_boolean_t strict_node_history = FALSE; /* off by default */
svn_boolean_t include_merged_revisions = FALSE; /* off by default */
+
apr_array_header_t *revprops = apr_array_make(resource->pool, 3,
sizeof(const char *));
apr_array_header_t *paths
@@ -313,12 +352,10 @@ dav_svn__log_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
/* If this is still FALSE after the loop, we haven't seen either of
@@ -415,12 +452,15 @@ dav_svn__log_report(const dav_resource *resource,
/* Build log receiver baton */
lrb.bb = apr_brigade_create(resource->pool, /* not the subpool! */
- output->c->bucket_alloc);
+ dav_svn__output_get_bucket_alloc(output));
lrb.output = output;
lrb.needs_header = TRUE;
lrb.stack_depth = 0;
/* lrb.requested_custom_revprops set above */
+ lrb.result_count = 0;
+ lrb.next_forced_flush = 4;
+
/* Our svn_log_entry_receiver_t sends the <S:log-report> header in
a lazy fashion. Before writing the first log message, it assures
that the header has already been sent (checking the needs_header
@@ -443,7 +483,7 @@ dav_svn__log_report(const dav_resource *resource,
resource->pool);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
diff --git a/subversion/mod_dav_svn/reports/mergeinfo.c b/subversion/mod_dav_svn/reports/mergeinfo.c
index 15c3071..107c7a1 100644
--- a/subversion/mod_dav_svn/reports/mergeinfo.c
+++ b/subversion/mod_dav_svn/reports/mergeinfo.c
@@ -46,7 +46,7 @@
dav_error *
dav_svn__get_mergeinfo_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_error_t *serr;
dav_error *derr = NULL;
@@ -73,12 +73,10 @@ dav_svn__get_mergeinfo_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have "
- "certain required elements.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "certain required elements");
}
for (child = doc->root->first_child; child != NULL; child = child->next)
@@ -126,7 +124,8 @@ dav_svn__get_mergeinfo_report(const dav_resource *resource,
arb.repos = resource->info->repos;
/* Build mergeinfo brigade */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
serr = svn_repos_fs_get_mergeinfo(&catalog, repos->repos, paths, rev,
inherit, include_descendants,
@@ -134,7 +133,7 @@ dav_svn__get_mergeinfo_report(const dav_resource *resource,
&arb, resource->pool);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
@@ -144,7 +143,7 @@ dav_svn__get_mergeinfo_report(const dav_resource *resource,
resource->pool);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
@@ -162,7 +161,7 @@ dav_svn__get_mergeinfo_report(const dav_resource *resource,
"xmlns:D=\"DAV:\">" DEBUG_CR);
if (serr)
{
- derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
+ derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
resource->pool);
goto cleanup;
}
diff --git a/subversion/mod_dav_svn/reports/replay.c b/subversion/mod_dav_svn/reports/replay.c
index 0d57f32..886dbba 100644
--- a/subversion/mod_dav_svn/reports/replay.c
+++ b/subversion/mod_dav_svn/reports/replay.c
@@ -44,7 +44,7 @@
typedef struct edit_baton_t {
apr_bucket_brigade *bb;
- ap_filter_t *output;
+ dav_svn__output *output;
svn_boolean_t started;
svn_boolean_t sending_textdelta;
int compression_level;
@@ -108,7 +108,7 @@ add_file_or_directory(const char *file_or_directory,
SVN_ERR(maybe_close_textdelta(eb));
- *added_baton = (void *)eb;
+ *added_baton = eb;
if (! copyfrom_path)
SVN_ERR(dav_svn__brigade_printf(eb->bb, eb->output,
@@ -135,7 +135,7 @@ open_file_or_directory(const char *file_or_directory,
{
const char *qname = apr_xml_quote_string(pool, path, 1);
SVN_ERR(maybe_close_textdelta(eb));
- *opened_baton = (void *)eb;
+ *opened_baton = eb;
return dav_svn__brigade_printf(eb->bb, eb->output,
"<S:open-%s name=\"%s\" rev=\"%ld\"/>"
DEBUG_CR,
@@ -367,7 +367,7 @@ static void
make_editor(const svn_delta_editor_t **editor,
void **edit_baton,
apr_bucket_brigade *bb,
- ap_filter_t *output,
+ dav_svn__output *output,
int compression_level,
apr_pool_t *pool)
{
@@ -401,20 +401,19 @@ make_editor(const svn_delta_editor_t **editor,
static dav_error *
malformed_element_error(const char *tagname, apr_pool_t *pool)
{
- return dav_svn__new_error_tag(pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(pool, HTTP_BAD_REQUEST, 0,
apr_pstrcat(pool,
"The request's '", tagname,
"' element is malformed; there "
"is a problem with the client.",
- (char *)NULL),
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
+ SVN_VA_NULL));
}
dav_error *
dav_svn__replay_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
dav_error *derr = NULL;
svn_revnum_t low_water_mark = SVN_INVALID_REVNUM;
@@ -456,13 +455,11 @@ dav_svn__replay_report(const dav_resource *resource,
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have an "
"svn:revision element. That element is "
- "required.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "required");
for (child = doc->root->first_child; child != NULL; child = child->next)
{
@@ -521,21 +518,20 @@ dav_svn__replay_report(const dav_resource *resource,
}
if (! SVN_IS_VALID_REVNUM(rev))
- return dav_svn__new_error_tag
+ return dav_svn__new_error_svn
(resource->pool, HTTP_BAD_REQUEST, 0,
- "Request was missing the revision argument.",
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
+ "Request was missing the revision argument");
if (! SVN_IS_VALID_REVNUM(low_water_mark))
- return dav_svn__new_error_tag
+ return dav_svn__new_error_svn
(resource->pool, HTTP_BAD_REQUEST, 0,
- "Request was missing the low-water-mark argument.",
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
+ "Request was missing the low-water-mark argument");
if (! base_dir)
base_dir = "";
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
if ((err = svn_fs_revision_root(&root, resource->info->repos->fs, rev,
resource->pool)))
diff --git a/subversion/mod_dav_svn/reports/update.c b/subversion/mod_dav_svn/reports/update.c
index 541d551..70be92e 100644
--- a/subversion/mod_dav_svn/reports/update.c
+++ b/subversion/mod_dav_svn/reports/update.c
@@ -68,7 +68,7 @@ typedef struct update_ctx_t {
apr_bucket_brigade *bb;
/* where to deliver the output */
- ap_filter_t *output;
+ dav_svn__output *output;
/* where do these editor paths *really* point to? */
apr_hash_t *pathmap;
@@ -127,10 +127,6 @@ typedef struct item_baton_t {
/* File/dir copied? */
svn_boolean_t copyfrom;
- /* Does the client need to fetch additional properties for this
- item? */
- svn_boolean_t fetch_props;
-
/* Array of const char * names of removed properties. (Used only
for copied files/dirs in skelta mode.) */
apr_array_header_t *removed_props;
@@ -257,13 +253,13 @@ send_vsn_url(item_baton_t *baton, apr_pool_t *pool)
{
href = dav_svn__build_uri(baton->uc->resource->info->repos,
DAV_SVN__BUILD_URI_REVROOT,
- revision, path, 0 /* add_href */, pool);
+ revision, path, FALSE /* add_href */, pool);
}
else
{
href = dav_svn__build_uri(baton->uc->resource->info->repos,
DAV_SVN__BUILD_URI_VERSION,
- revision, path, 0 /* add_href */, pool);
+ revision, path, FALSE /* add_href */, pool);
}
return dav_svn__brigade_printf(baton->uc->bb, baton->uc->output,
@@ -321,7 +317,6 @@ add_helper(svn_boolean_t is_dir,
{
item_baton_t *child;
update_ctx_t *uc = parent->uc;
- const char *bc_url = NULL;
child = make_child_baton(parent, path, pool);
child->added = TRUE;
@@ -345,12 +340,14 @@ add_helper(svn_boolean_t is_dir,
{
/* we send baseline-collection urls when we add a directory */
svn_revnum_t revision;
+ const char *bc_url;
+
revision = dav_svn__get_safe_cr(child->uc->rev_root, real_path,
pool);
bc_url = dav_svn__build_uri(child->uc->resource->info->repos,
DAV_SVN__BUILD_URI_BC,
revision, real_path,
- 0 /* add_href */, pool);
+ FALSE /* add_href */, pool);
bc_url = svn_urlpath__canonicalize(bc_url, pool);
/* ugh, build_uri ignores the path and just builds the root
@@ -364,6 +361,8 @@ add_helper(svn_boolean_t is_dir,
/* make sure that the BC_URL is xml attribute safe. */
bc_url = apr_xml_quote_string(pool, bc_url, 1);
+
+ bc_url_str = apr_psprintf(pool, " bc-url=\"%s\"", bc_url);
}
else
{
@@ -377,9 +376,6 @@ add_helper(svn_boolean_t is_dir,
svn_checksum_to_cstring(sha1_checksum, pool));
}
- if (bc_url)
- bc_url_str = apr_psprintf(pool, " bc-url=\"%s\"", bc_url);
-
if (copyfrom_path == NULL)
{
elt = apr_psprintf(pool,
@@ -466,12 +462,6 @@ close_helper(svn_boolean_t is_dir, item_baton_t *baton, apr_pool_t *pool)
}
}
- /* If our client need to fetch properties, let it know. */
- if (baton->fetch_props)
- SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output,
- "<S:fetch-props/>" DEBUG_CR));
-
-
/* Let's tie it off, nurse. */
if (baton->added)
SVN_ERR(dav_svn__brigade_printf(baton->uc->bb, baton->uc->output,
@@ -913,9 +903,8 @@ malformed_element_error(const char *tagname, apr_pool_t *pool)
const char *errstr = apr_pstrcat(pool, "The request's '", tagname,
"' element is malformed; there "
"is a problem with the client.",
- (char *)NULL);
- return dav_svn__new_error_tag(pool, HTTP_BAD_REQUEST, 0, errstr,
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
+ SVN_VA_NULL);
+ return dav_svn__new_error_svn(pool, HTTP_BAD_REQUEST, 0, errstr);
}
@@ -934,7 +923,7 @@ validate_input_revision(svn_revnum_t revision,
const dav_resource *resource)
{
if (! SVN_IS_VALID_REVNUM(revision))
- return SVN_NO_ERROR;
+ return NULL;
if (revision > youngest)
{
@@ -958,14 +947,14 @@ validate_input_revision(svn_revnum_t revision,
"Invalid revision found in update report "
"request.", resource->pool);
}
- return SVN_NO_ERROR;
+ return NULL;
}
dav_error *
dav_svn__update_report(const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_delta_editor_t *editor;
apr_xml_elem *child;
@@ -999,22 +988,18 @@ dav_svn__update_report(const dav_resource *resource,
if ((resource->info->restype != DAV_SVN_RESTYPE_VCC)
&& (resource->info->restype != DAV_SVN_RESTYPE_ME))
- return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT, 0,
"This report can only be run against "
- "a VCC or root-stub URI.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "a VCC or root-stub URI");
ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (ns == -1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
"The request does not contain the 'svn:' "
"namespace, so it is not going to have an "
"svn:target-revision element. That element "
- "is required.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "is required");
}
/* SVNAllowBulkUpdates On/Prefer: server configuration permits bulk updates
@@ -1152,6 +1137,11 @@ dav_svn__update_report(const dav_resource *resource,
}
if (child->ns == ns && strcmp(child->name, "resource-walk") == 0)
{
+ /* This flag is not used since Subversion 1.1.x
+ There are some remains in libsvn_ra_neon, where it can
+ be enabled via a static function flag.
+ Disabled since r852220 (aka r12146)
+ "Prefer correctness over efficiency." */
cdata = dav_xml_get_cdata(child, resource->pool, 1);
if (! *cdata)
return malformed_element_error(child->name, resource->pool);
@@ -1200,12 +1190,10 @@ dav_svn__update_report(const dav_resource *resource,
sending a style of report that we no longer allow. */
if (! src_path)
{
- return dav_svn__new_error_tag
+ return dav_svn__new_error_svn
(resource->pool, HTTP_BAD_REQUEST, 0,
"The request did not contain the '<src-path>' element.\n"
- "This may indicate that your client is too old.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "This may indicate that your client is too old");
}
uc.svndiff_version = resource->info->svndiff_version;
@@ -1214,7 +1202,8 @@ dav_svn__update_report(const dav_resource *resource,
uc.output = output;
uc.anchor = src_path;
uc.target = target;
- uc.bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
+ uc.bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
uc.pathmap = NULL;
uc.enable_v2_response = ((resource->info->restype == DAV_SVN_RESTYPE_ME)
&& (resource->info->repos->v2_protocol));
diff --git a/subversion/mod_dav_svn/repos.c b/subversion/mod_dav_svn/repos.c
index 590cca9..9bf5ea0 100644
--- a/subversion/mod_dav_svn/repos.c
+++ b/subversion/mod_dav_svn/repos.c
@@ -56,6 +56,7 @@
#include "private/svn_log.h"
#include "private/svn_fspath.h"
#include "private/svn_repos_private.h"
+#include "private/svn_sorts_private.h"
#include "dav_svn.h"
@@ -899,7 +900,7 @@ prep_version(dav_resource_combined *comb)
comb->res.uri = dav_svn__build_uri(comb->priv.repos,
DAV_SVN__BUILD_URI_BASELINE,
comb->priv.root.rev, NULL,
- 0 /* add_href */,
+ FALSE /* add_href */,
pool);
return NULL;
@@ -1034,6 +1035,28 @@ prep_working(dav_resource_combined *comb)
comb->res.exists = (kind != svn_node_none);
comb->res.collection = (kind == svn_node_dir);
+ if (comb->res.exists
+ && comb->priv.r->method_number == M_MKCOL
+ && comb->priv.repos->is_svn_client)
+ {
+ /* mod_dav will now continue returning a generic HTTP_METHOD_NOT_ALLOWED
+ error, which doesn't produce nice output on SVN, nor gives any details
+ on why the operation failed.
+
+ Let's error out a bit earlier and produce an error message that is
+ easier to understand for both clients and users. */
+
+ /* It would be nice if we could error out a bit later (see issue #2295),
+ like in create_collection(), but mod_dav outsmarts us by just
+ returning the error when the node exists. */
+
+ return dav_svn__convert_err(
+ svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+ "Path already exists, path '%s'",
+ comb->priv.repos_path),
+ HTTP_METHOD_NOT_ALLOWED, NULL, pool);
+ }
+
return NULL;
}
@@ -1168,7 +1191,7 @@ create_private_resource(const dav_resource *base,
if (base->info->repos->root_path[1])
comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path,
- path->data, (char *)NULL);
+ path->data, SVN_VA_NULL);
else
comb->res.uri = path->data;
comb->res.info = &comb->priv;
@@ -1208,14 +1231,15 @@ static void log_warning(void *baton, svn_error_t *err)
AP_MODULE_DECLARE(dav_error *)
-dav_svn_split_uri(request_rec *r,
- const char *uri_to_split,
- const char *root_path,
- const char **cleaned_uri,
- int *trailing_slash,
- const char **repos_basename,
- const char **relative_path,
- const char **repos_path)
+dav_svn_split_uri2(request_rec *r,
+ const char *uri_to_split,
+ const char *root_path,
+ const char **cleaned_uri,
+ int *trailing_slash,
+ const char **repos_basename,
+ const char **relative_path,
+ const char **repos_path,
+ apr_pool_t *pool)
{
apr_size_t len1;
int had_slash;
@@ -1231,7 +1255,7 @@ dav_svn_split_uri(request_rec *r,
if ((fs_path == NULL) && (fs_parent_path == NULL))
{
/* ### are SVN_ERR_APMOD codes within the right numeric space? */
- return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ return dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR,
SVN_ERR_APMOD_MISSING_PATH_TO_FS,
"The server is misconfigured: "
"either an SVNPath or SVNParentPath "
@@ -1240,7 +1264,7 @@ dav_svn_split_uri(request_rec *r,
}
/* make a copy so that we can do some work on it */
- uri = apr_pstrdup(r->pool, uri_to_split);
+ uri = apr_pstrdup(pool, uri_to_split);
/* remove duplicate slashes, and make sure URI has no trailing '/' */
ap_no2slash(uri);
@@ -1255,7 +1279,7 @@ dav_svn_split_uri(request_rec *r,
*trailing_slash = FALSE;
/* return the first item. */
- *cleaned_uri = apr_pstrdup(r->pool, uri);
+ *cleaned_uri = apr_pstrdup(pool, uri);
/* The URL space defined by the SVN provider is always a virtual
space. Construct the path relative to the configured Location
@@ -1296,7 +1320,7 @@ dav_svn_split_uri(request_rec *r,
if (fs_path != NULL)
{
/* the repos_basename is the last component of root_path. */
- *repos_basename = svn_dirent_basename(root_path, r->pool);
+ *repos_basename = svn_dirent_basename(root_path, pool);
/* 'relative' is already correct for SVNPath; the root_path
already contains the name of the repository, so relative is
@@ -1314,7 +1338,7 @@ dav_svn_split_uri(request_rec *r,
if (relative[1] == '\0')
{
/* ### are SVN_ERR_APMOD codes within the right numeric space? */
- return dav_svn__new_error(r->pool, HTTP_FORBIDDEN,
+ return dav_svn__new_error(pool, HTTP_FORBIDDEN,
SVN_ERR_APMOD_MALFORMED_URI,
"The URI does not contain the name "
"of a repository.");
@@ -1331,7 +1355,7 @@ dav_svn_split_uri(request_rec *r,
}
else
{
- magic_component = apr_pstrndup(r->pool, relative + 1,
+ magic_component = apr_pstrndup(pool, relative + 1,
magic_end - relative - 1);
relative = magic_end;
}
@@ -1341,7 +1365,7 @@ dav_svn_split_uri(request_rec *r,
}
/* We can return 'relative' at this point too. */
- *relative_path = apr_pstrdup(r->pool, relative);
+ *relative_path = apr_pstrdup(pool, relative);
/* Code to remove the !svn junk from the front of the relative path,
mainly stolen from parse_uri(). This code assumes that
@@ -1362,7 +1386,7 @@ dav_svn_split_uri(request_rec *r,
if (ch == '\0')
{
/* relative is just "!svn", which is malformed. */
- return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ return dav_svn__new_error(pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Nothing follows the svn special_uri.");
}
@@ -1389,7 +1413,7 @@ dav_svn_split_uri(request_rec *r,
*repos_path = NULL;
else
return dav_svn__new_error(
- r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Missing info after special_uri.");
}
@@ -1413,7 +1437,7 @@ dav_svn_split_uri(request_rec *r,
/* Did we break from the loop prematurely? */
if (j != (defn->numcomponents - 1))
return dav_svn__new_error(
- r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Not enough components after "
"special_uri.");
@@ -1427,13 +1451,13 @@ dav_svn_split_uri(request_rec *r,
else
{
/* Found a slash after the special components. */
- *repos_path = apr_pstrdup(r->pool, start);
+ *repos_path = apr_pstrdup(pool, start - 1);
}
}
else
{
return
- dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ dav_svn__new_error(pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Unknown data after special_uri.");
}
@@ -1444,7 +1468,7 @@ dav_svn_split_uri(request_rec *r,
if (defn->name == NULL)
return
- dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
+ dav_svn__new_error(pool, HTTP_NOT_FOUND,
SVN_ERR_APMOD_MALFORMED_URI,
"Couldn't match subdir after special_uri.");
}
@@ -1453,13 +1477,27 @@ dav_svn_split_uri(request_rec *r,
{
/* There's no "!svn/" at all, so the relative path is already
a valid path within the repository. */
- *repos_path = apr_pstrdup(r->pool, relative);
+ *repos_path = apr_pstrdup(pool, relative - 1);
}
}
return NULL;
}
+AP_MODULE_DECLARE(dav_error *)
+dav_svn_split_uri(request_rec *r,
+ const char *uri_to_split,
+ const char *root_path,
+ const char **cleaned_uri,
+ int *trailing_slash,
+ const char **repos_basename,
+ const char **relative_path,
+ const char **repos_path)
+{
+ return dav_svn_split_uri2(r, uri_to_split, root_path, cleaned_uri,
+ trailing_slash, repos_basename, relative_path,
+ repos_path, r->pool);
+}
/* Context for cleanup handler. */
struct cleanup_fs_access_baton
@@ -1530,7 +1568,7 @@ get_parentpath_resource(request_rec *r,
if (r->uri[len-1] != '/')
{
new_uri = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
- "/", (char *)NULL);
+ "/", SVN_VA_NULL);
apr_table_setn(r->headers_out, "Location",
ap_construct_url(r->pool, new_uri, r));
return dav_svn__new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
@@ -1820,9 +1858,24 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
"Attempting to modify out-of-date resource.",
r->pool);
}
+ else if (comb->priv.version_name > created_rev)
+ {
+ svn_revnum_t txn_base_rev;
+
+ txn_base_rev = svn_fs_txn_base_revision(comb->res.info->root.txn);
+ if (comb->priv.version_name > txn_base_rev)
+ {
+ serr = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ "No such revision %ld",
+ comb->priv.version_name);
+
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Unknown base revision",
+ r->pool);
+ }
+ }
}
- else if (SVN_IS_VALID_REVNUM(comb->priv.version_name)
- && comb->res.collection)
+ else if (comb->res.collection)
{
/* Issue #4480: With HTTPv2 we can receive the first change for a
directory after it has been made mutable, because one of its
@@ -1837,7 +1890,7 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
properties changed since the BASE version.
### I think svn_fs_node_relation() checks for more changes than we
- should check for here. Needs further review. But it looks like\
+ should check for here. Needs further review. But it looks like
this check matches the checks in the libsvn_fs commit editor.
For now I would say reporting out of date in a few too many
@@ -1846,8 +1899,7 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
svn_revnum_t txn_base_rev;
svn_fs_root_t *txn_base_root;
svn_fs_root_t *rev_root;
- const svn_fs_id_t *txn_base_id;
- const svn_fs_id_t *rev_id;
+ svn_fs_node_relation_t node_relation;
txn_base_rev = svn_fs_txn_base_revision(comb->res.info->root.txn);
@@ -1856,15 +1908,11 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
serr = svn_fs_revision_root(&txn_base_root, comb->res.info->repos->fs,
txn_base_rev, r->pool);
-
- if (!serr)
- serr = svn_fs_node_id(&txn_base_id, txn_base_root,
- comb->priv.repos_path, r->pool);
if (serr != NULL)
{
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
- "Could not open youngest revision root "
+ "Could not open the transaction revision "
"for verification against the base "
"revision", r->pool);
}
@@ -1872,22 +1920,35 @@ do_out_of_date_check(dav_resource_combined *comb, request_rec *r)
serr = svn_fs_revision_root(&rev_root, comb->res.info->repos->fs,
comb->priv.version_name, r->pool);
- if (!serr)
- serr = svn_fs_node_id(&rev_id, rev_root,
- comb->priv.repos_path, r->pool);
-
if (serr != NULL)
{
+ svn_fs_close_root(txn_base_root);
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
- "Could not open the base revision"
- "for verification against the youngest "
- "revision", r->pool);
+ "Could not open the base revision "
+ "for verification against the "
+ "transaction revision", r->pool);
}
+ serr = svn_fs_node_relation(&node_relation, rev_root,
+ comb->priv.repos_path,
+ txn_base_root,
+ comb->priv.repos_path,
+ r->pool);
+
svn_fs_close_root(rev_root);
svn_fs_close_root(txn_base_root);
- if (0 != svn_fs_compare_ids(txn_base_id, rev_id))
+ if (serr != NULL)
+ {
+ /* ### correct HTTP error? */
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Unable to fetch the node revision id "
+ "of the version resource within the "
+ "revision",
+ r->pool);
+ }
+
+ if (node_relation != svn_fs_node_unchanged)
{
serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
"Directory '%s' is out of date",
@@ -2065,6 +2126,16 @@ get_resource(request_rec *r,
xslt_uri = dav_svn__get_xslt_uri(r);
fs_parent_path = dav_svn__get_fs_parent_path(r);
+ if (r->method_number == M_COPY)
+ {
+ /* Workaround for issue #4531: Avoid a depth-infinity walk on
+ the copy source by overriding the Depth header here.
+ mod_dav defaults to infinite depth if this header is not set
+ which makes copies O(size of source) rather than the desired O(1).
+ ### Should be fixed by an explicit provider API feature in mod_dav. */
+ apr_table_setn(r->headers_in, "Depth", "0");
+ }
+
/* Special case: detect and build the SVNParentPath as a unique type
of private resource, iff the SVNListParentPath directive is 'on'. */
if (dav_svn__is_parentpath_list(r))
@@ -2261,7 +2332,7 @@ get_resource(request_rec *r,
}
/* Retrieve/cache open repository */
- repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, (char *)NULL);
+ repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, SVN_VA_NULL);
apr_pool_userdata_get(&userdata, repos_key, r->connection->pool);
repos->repos = userdata;
if (repos->repos == NULL)
@@ -2275,7 +2346,9 @@ get_resource(request_rec *r,
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
dav_svn__get_fulltext_cache_flag(r) ? "1" :"0");
svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
- dav_svn__get_revprop_cache_flag(r) ? "1" :"0");
+ dav_svn__get_revprop_cache_flag(r) ? "2" :"0");
+ svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
+ dav_svn__get_block_read_flag(r) ? "1" :"0");
/* Disallow BDB/event until issue 4157 is fixed. */
if (!strcmp(ap_show_mpm(), "event"))
@@ -2298,8 +2371,8 @@ get_resource(request_rec *r,
/* open the FS */
if (!serr)
- serr = svn_repos_open2(&(repos->repos), fs_path, fs_config,
- r->connection->pool);
+ serr = svn_repos_open3(&(repos->repos), fs_path, fs_config,
+ r->connection->pool, r->pool);
if (serr != NULL)
{
/* The error returned by svn_repos_open2 might contain the
@@ -2307,9 +2380,16 @@ get_resource(request_rec *r,
leak that path back to the client, because that would be
a security risk, but we do want to log the real error on
the server side. */
- return dav_svn__sanitize_error(serr, "Could not open the requested "
- "SVN filesystem",
- HTTP_INTERNAL_SERVER_ERROR, r);
+
+ apr_status_t cause = svn_error_root_cause(serr)->apr_err;
+ if (APR_STATUS_IS_ENOENT(cause) || APR_STATUS_IS_ENOTDIR(cause))
+ return dav_svn__sanitize_error(
+ serr, "Could not find the requested SVN filesystem",
+ HTTP_NOT_FOUND, r);
+ else
+ return dav_svn__sanitize_error(
+ serr, "Could not open the requested SVN filesystem",
+ HTTP_INTERNAL_SERVER_ERROR, r);
}
/* Cache the open repos for the next request on this connection */
@@ -2467,7 +2547,7 @@ get_resource(request_rec *r,
"/",
r->args ? "?" : "",
r->args ? r->args : "",
- (char *)NULL);
+ SVN_VA_NULL);
apr_table_setn(r->headers_out, "Location",
ap_construct_url(r->pool, new_path, r));
return dav_svn__new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
@@ -3161,8 +3241,8 @@ set_headers(request_rec *r, const dav_resource *resource)
typedef struct diff_ctx_t {
- ap_filter_t *output;
- apr_pool_t *pool;
+ dav_svn__output *output;
+ apr_bucket_brigade *bb;
} diff_ctx_t;
@@ -3170,18 +3250,9 @@ static svn_error_t * __attribute__((warn_unused_result))
write_to_filter(void *baton, const char *buffer, apr_size_t *len)
{
diff_ctx_t *dc = baton;
- apr_bucket_brigade *bb;
- apr_bucket *bkt;
- apr_status_t status;
/* take the current data and shove it into the filter */
- bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc);
- bkt = apr_bucket_transient_create(buffer, *len, dc->output->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS) {
- return svn_error_create(status, NULL,
- "Could not write data to filter");
- }
+ SVN_ERR(dav_svn__brigade_write(dc->bb, dc->output, buffer, *len));
return SVN_NO_ERROR;
}
@@ -3191,28 +3262,270 @@ static svn_error_t * __attribute__((warn_unused_result))
close_filter(void *baton)
{
diff_ctx_t *dc = baton;
- apr_bucket_brigade *bb;
apr_bucket *bkt;
- apr_status_t status;
/* done with the file. write an EOS bucket now. */
- bb = apr_brigade_create(dc->pool, dc->output->c->bucket_alloc);
- bkt = apr_bucket_eos_create(dc->output->c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(dc->output, bb)) != APR_SUCCESS)
- return svn_error_create(status, NULL, "Could not write EOS to filter");
+ bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(dc->output));
+ APR_BRIGADE_INSERT_TAIL(dc->bb, bkt);
+ SVN_ERR(dav_svn__output_pass_brigade(dc->output, dc->bb));
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+emit_collection_head(const dav_resource *resource,
+ apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ svn_boolean_t gen_html,
+ apr_pool_t *pool)
+{
+ /* XML schema for the directory index if xslt_uri is set:
+
+ <?xml version="1.0"?>
+ <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */
+ static const char xml_index_dtd[] =
+ "<!DOCTYPE svn [\n"
+ " <!ELEMENT svn (index)>\n"
+ " <!ATTLIST svn version CDATA #REQUIRED\n"
+ " href CDATA #REQUIRED>\n"
+ " <!ELEMENT index (updir?, (file | dir)*)>\n"
+ " <!ATTLIST index name CDATA #IMPLIED\n"
+ " path CDATA #IMPLIED\n"
+ " rev CDATA #IMPLIED\n"
+ " base CDATA #IMPLIED>\n"
+ " <!ELEMENT updir EMPTY>\n"
+ " <!ATTLIST updir href CDATA #REQUIRED>\n"
+ " <!ELEMENT file EMPTY>\n"
+ " <!ATTLIST file name CDATA #REQUIRED\n"
+ " href CDATA #REQUIRED>\n"
+ " <!ELEMENT dir EMPTY>\n"
+ " <!ATTLIST dir name CDATA #REQUIRED\n"
+ " href CDATA #REQUIRED>\n"
+ "]>\n";
+
+ if (gen_html)
+ {
+ const char *title;
+ if (resource->info->repos_path == NULL)
+ title = "unknown location";
+ else
+ title = resource->info->repos_path;
+
+ if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
+ {
+ if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
+ title = apr_psprintf(pool,
+ "Revision %ld: %s",
+ resource->info->root.rev, title);
+ if (resource->info->repos->repo_basename)
+ title = apr_psprintf(pool, "%s - %s",
+ resource->info->repos->repo_basename,
+ title);
+ if (resource->info->repos->repo_name)
+ title = apr_psprintf(pool, "%s: %s",
+ resource->info->repos->repo_name,
+ title);
+ }
+
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ "<html><head><title>%s</title></head>\n"
+ "<body>\n <h2>%s</h2>\n <ul>\n",
+ title, title));
+ }
+ else
+ {
+ const char *name = resource->info->repos->repo_name;
+ const char *href = resource->info->repos_path;
+ const char *base = resource->info->repos->repo_basename;
+
+ SVN_ERR(dav_svn__brigade_puts(bb, output, "<?xml version=\"1.0\"?>\n"));
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ "<?xml-stylesheet type=\"text/xsl\" "
+ "href=\"%s\"?>\n",
+ resource->info->repos->xslt_uri));
+ SVN_ERR(dav_svn__brigade_puts(bb, output, xml_index_dtd));
+ SVN_ERR(dav_svn__brigade_puts(bb, output,
+ "<svn version=\"" SVN_VERSION "\"\n"
+ " href=\"http://subversion.apache.org/\">\n"));
+ SVN_ERR(dav_svn__brigade_puts(bb, output, " <index"));
+
+ if (name)
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " name=\"%s\"",
+ apr_xml_quote_string(resource->pool,
+ name, 1)));
+ if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
+ SVN_ERR(dav_svn__brigade_printf(bb, output, " rev=\"%ld\"",
+ resource->info->root.rev));
+ if (href)
+ SVN_ERR(dav_svn__brigade_printf(bb, output, " path=\"%s\"",
+ apr_xml_quote_string(resource->pool,
+ href, 1)));
+ if (base)
+ SVN_ERR(dav_svn__brigade_printf(bb, output, " base=\"%s\"", base));
+
+ SVN_ERR(dav_svn__brigade_puts(bb, output, ">\n"));
+ }
+
+ if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
+ && resource->info->repos_path
+ && ((resource->info->repos_path[1] != '\0')
+ || dav_svn__get_list_parentpath_flag(resource->info->r)))
+ {
+ const char *href;
+ if (resource->info->pegged)
+ {
+ href = apr_psprintf(pool, "../?p=%ld", resource->info->root.rev);
+ }
+ else
+ {
+ href = "../";
+ }
+
+ if (gen_html)
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <li><a href=\"%s\">..</a></li>\n",
+ href));
+ }
+ else
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <updir href=\"%s\"/>\n",
+ href));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+emit_collection_entry(const dav_resource *resource,
+ apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ const svn_fs_dirent_t *entry,
+ svn_boolean_t gen_html,
+ apr_pool_t *pool)
+{
+ const char *name = entry->name;
+ const char *href = name;
+ svn_boolean_t is_dir = (entry->kind == svn_node_dir);
+
+ /* append a trailing slash onto the name for directories. we NEED
+ this for the href portion so that the relative reference will
+ descend properly. for the visible portion, it is just nice. */
+ /* ### The xml output doesn't like to see a trailing slash on
+ ### the visible portion, so avoid that. */
+ if (is_dir)
+ href = apr_pstrcat(pool, href, "/", SVN_VA_NULL);
+
+ if (gen_html)
+ name = href;
+
+ /* We quote special characters in both XML and HTML. */
+ name = apr_xml_quote_string(pool, name, !gen_html);
+
+ /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path()
+ behaves differently on different platforms. It claims to
+ "convert an OS path to a URL in an OS dependant way".
+ Nevertheless, there appears to be only one implementation
+ of the function in httpd, and the code seems completely
+ platform independent, so we'll assume it's appropriate for
+ mod_dav_svn to use it to quote outbound paths. */
+ href = ap_os_escape_path(pool, href, 0);
+ href = apr_xml_quote_string(pool, href, 1);
+
+ if (gen_html)
+ {
+ /* If our directory was access using the public peg-rev
+ CGI query interface, we'll let its dirents carry that
+ peg-rev, too. */
+ if (resource->info->pegged)
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <li><a href=\"%s?p=%ld\">%s</a></li>\n",
+ href, resource->info->root.rev, name));
+ }
+ else
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <li><a href=\"%s\">%s</a></li>\n",
+ href, name));
+ }
+ }
+ else
+ {
+ const char *const tag = (is_dir ? "dir" : "file");
+
+ /* This is where we could search for props */
+
+ /* If our directory was access using the public peg-rev
+ CGI query interface, we'll let its dirents carry that
+ peg-rev, too. */
+ if (resource->info->pegged)
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <%s name=\"%s\" href=\"%s?p=%ld\" />\n",
+ tag, name, href, resource->info->root.rev));
+ }
+ else
+ {
+ SVN_ERR(dav_svn__brigade_printf(bb, output,
+ " <%s name=\"%s\" href=\"%s\" />\n",
+ tag, name, href));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+emit_collection_tail(const dav_resource *resource,
+ apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ svn_boolean_t gen_html,
+ apr_pool_t *pool)
+{
+ if (gen_html)
+ {
+ if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0)
+ {
+ /* Apache's signature generation code didn't eat our prefix.
+ ServerSignature must be enabled. Print our version info.
+
+ WARNING: This is a kludge!! ap_psignature() doesn't promise
+ to return the empty string when ServerSignature is off. We
+ know it does by code inspection, but this behavior is subject
+ to change. (Perhaps we should try to get the Apache folks to
+ make this promise, though. Seems harmless/useful enough...)
+ */
+ SVN_ERR(dav_svn__brigade_puts(bb, output,
+ " </ul>\n <hr noshade><em>Powered by "
+ "<a href=\"http://subversion.apache.org/\">"
+ "Apache Subversion"
+ "</a> version " SVN_VERSION "."
+ "</em>\n</body></html>"));
+ }
+ else
+ SVN_ERR(dav_svn__brigade_puts(bb, output, " </ul>\n</body></html>"));
+ }
+ else
+ SVN_ERR(dav_svn__brigade_puts(bb, output, " </index>\n</svn>\n"));
return SVN_NO_ERROR;
}
static dav_error *
-deliver(const dav_resource *resource, ap_filter_t *output)
+deliver(const dav_resource *resource, ap_filter_t *unused)
{
svn_error_t *serr;
apr_bucket_brigade *bb;
apr_bucket *bkt;
- apr_status_t status;
+ dav_svn__output *output;
/* Check resource type */
if (resource->baselined
@@ -3225,39 +3538,17 @@ deliver(const dav_resource *resource, ap_filter_t *output)
"Cannot GET this type of resource.");
}
+ output = dav_svn__output_create(resource->info->r, resource->pool);
+
if (resource->collection)
{
const int gen_html = !resource->info->repos->xslt_uri;
apr_hash_t *entries;
- apr_pool_t *entry_pool;
+ apr_pool_t *iterpool;
apr_array_header_t *sorted;
svn_revnum_t dir_rev = SVN_INVALID_REVNUM;
int i;
- /* XML schema for the directory index if xslt_uri is set:
-
- <?xml version="1.0"?>
- <?xml-stylesheet type="text/xsl" href="[info->repos->xslt_uri]"?> */
- static const char xml_index_dtd[] =
- "<!DOCTYPE svn [\n"
- " <!ELEMENT svn (index)>\n"
- " <!ATTLIST svn version CDATA #REQUIRED\n"
- " href CDATA #REQUIRED>\n"
- " <!ELEMENT index (updir?, (file | dir)*)>\n"
- " <!ATTLIST index name CDATA #IMPLIED\n"
- " path CDATA #IMPLIED\n"
- " rev CDATA #IMPLIED\n"
- " base CDATA #IMPLIED>\n"
- " <!ELEMENT updir EMPTY>\n"
- " <!ATTLIST updir href CDATA #REQUIRED>\n"
- " <!ELEMENT file EMPTY>\n"
- " <!ATTLIST file name CDATA #REQUIRED\n"
- " href CDATA #REQUIRED>\n"
- " <!ELEMENT dir EMPTY>\n"
- " <!ATTLIST dir name CDATA #REQUIRED\n"
- " href CDATA #REQUIRED>\n"
- "]>\n";
-
/* <svn version="1.3.0 (dev-build)"
href="http://subversion.apache.org">
<index name="[info->repos->repo_name]"
@@ -3338,99 +3629,21 @@ deliver(const dav_resource *resource, ap_filter_t *output)
resource->pool);
}
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
-
- if (gen_html)
- {
- const char *title;
- if (resource->info->repos_path == NULL)
- title = "unknown location";
- else
- title = resource->info->repos_path;
-
- if (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
- {
- if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
- title = apr_psprintf(resource->pool,
- "Revision %ld: %s",
- resource->info->root.rev, title);
- if (resource->info->repos->repo_basename)
- title = apr_psprintf(resource->pool, "%s - %s",
- resource->info->repos->repo_basename,
- title);
- if (resource->info->repos->repo_name)
- title = apr_psprintf(resource->pool, "%s: %s",
- resource->info->repos->repo_name,
- title);
- }
-
- ap_fprintf(output, bb, "<html><head><title>%s</title></head>\n"
- "<body>\n <h2>%s</h2>\n <ul>\n", title, title);
- }
- else
- {
- const char *name = resource->info->repos->repo_name;
- const char *href = resource->info->repos_path;
- const char *base = resource->info->repos->repo_basename;
-
- ap_fputs(output, bb, "<?xml version=\"1.0\"?>\n");
- ap_fprintf(output, bb,
- "<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n",
- resource->info->repos->xslt_uri);
- ap_fputs(output, bb, xml_index_dtd);
- ap_fputs(output, bb,
- "<svn version=\"" SVN_VERSION "\"\n"
- " href=\"http://subversion.apache.org/\">\n");
- ap_fputs(output, bb, " <index");
- if (name)
- ap_fprintf(output, bb, " name=\"%s\"",
- apr_xml_quote_string(resource->pool, name, 1));
- if (SVN_IS_VALID_REVNUM(resource->info->root.rev))
- ap_fprintf(output, bb, " rev=\"%ld\"",
- resource->info->root.rev);
- if (href)
- ap_fprintf(output, bb, " path=\"%s\"",
- apr_xml_quote_string(resource->pool,
- href,
- 1));
- if (base)
- ap_fprintf(output, bb, " base=\"%s\"", base);
-
- ap_fputs(output, bb, ">\n");
- }
-
- if ((resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION)
- && resource->info->repos_path
- && ((resource->info->repos_path[1] != '\0')
- || dav_svn__get_list_parentpath_flag(resource->info->r)))
- {
- const char *href;
- if (resource->info->pegged)
- {
- href = apr_psprintf(resource->pool, "../?p=%ld",
- resource->info->root.rev);
- }
- else
- {
- href = "../";
- }
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
- if (gen_html)
- {
- ap_fprintf(output, bb,
- " <li><a href=\"%s\">..</a></li>\n", href);
- }
- else
- {
- ap_fprintf(output, bb, " <updir href=\"%s\"/>\n", href);
- }
- }
+ serr = emit_collection_head(resource, bb, output, gen_html,
+ resource->pool);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "could not output collection",
+ resource->pool);
/* get a sorted list of the entries */
sorted = svn_sort__hash(entries, svn_sort_compare_items_as_paths,
resource->pool);
- entry_pool = svn_pool_create(resource->pool);
+ iterpool = svn_pool_create(resource->pool);
for (i = 0; i < sorted->nelts; ++i)
{
@@ -3438,11 +3651,9 @@ deliver(const dav_resource *resource, ap_filter_t *output)
const svn_sort__item_t);
const svn_fs_dirent_t *entry = item->value;
const char *name = item->key;
- const char *href = name;
- svn_boolean_t is_dir = (entry->kind == svn_node_dir);
const char *repos_relpath = NULL;
- svn_pool_clear(entry_pool);
+ svn_pool_clear(iterpool);
/* DIR_REV is set to a valid revision if we're looking at
the entries of a versioned directory. Otherwise, we're
@@ -3450,120 +3661,45 @@ deliver(const dav_resource *resource, ap_filter_t *output)
if (SVN_IS_VALID_REVNUM(dir_rev))
{
repos_relpath = svn_fspath__join(resource->info->repos_path,
- name, entry_pool);
+ name, iterpool);
if (! dav_svn__allow_read(resource->info->r,
resource->info->repos,
repos_relpath,
dir_rev,
- entry_pool))
+ iterpool))
continue;
}
else
{
if (! dav_svn__allow_list_repos(resource->info->r,
- entry->name, entry_pool))
+ entry->name, iterpool))
continue;
}
- /* append a trailing slash onto the name for directories. we NEED
- this for the href portion so that the relative reference will
- descend properly. for the visible portion, it is just nice. */
- /* ### The xml output doesn't like to see a trailing slash on
- ### the visible portion, so avoid that. */
- if (is_dir)
- href = apr_pstrcat(entry_pool, href, "/", (char *)NULL);
-
- if (gen_html)
- name = href;
-
- /* We quote special characters in both XML and HTML. */
- name = apr_xml_quote_string(entry_pool, name, !gen_html);
-
- /* According to httpd-2.0.54/include/httpd.h, ap_os_escape_path()
- behaves differently on different platforms. It claims to
- "convert an OS path to a URL in an OS dependant way".
- Nevertheless, there appears to be only one implementation
- of the function in httpd, and the code seems completely
- platform independent, so we'll assume it's appropriate for
- mod_dav_svn to use it to quote outbound paths. */
- href = ap_os_escape_path(entry_pool, href, 0);
- href = apr_xml_quote_string(entry_pool, href, 1);
-
- if (gen_html)
- {
- /* If our directory was access using the public peg-rev
- CGI query interface, we'll let its dirents carry that
- peg-rev, too. */
- if (resource->info->pegged)
- {
- ap_fprintf(output, bb,
- " <li><a href=\"%s?p=%ld\">%s</a></li>\n",
- href, resource->info->root.rev, name);
- }
- else
- {
- ap_fprintf(output, bb,
- " <li><a href=\"%s\">%s</a></li>\n",
- href, name);
- }
- }
- else
- {
- const char *const tag = (is_dir ? "dir" : "file");
-
- /* This is where we could search for props */
-
- /* If our directory was access using the public peg-rev
- CGI query interface, we'll let its dirents carry that
- peg-rev, too. */
- if (resource->info->pegged)
- {
- ap_fprintf(output, bb,
- " <%s name=\"%s\" href=\"%s?p=%ld\" />\n",
- tag, name, href, resource->info->root.rev);
- }
- else
- {
- ap_fprintf(output, bb,
- " <%s name=\"%s\" href=\"%s\" />\n",
- tag, name, href);
- }
- }
+ serr = emit_collection_entry(resource, bb, output, entry, gen_html,
+ iterpool);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "could not output collection entry",
+ resource->pool);
}
- svn_pool_destroy(entry_pool);
+ svn_pool_destroy(iterpool);
- if (gen_html)
- {
- if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0)
- {
- /* Apache's signature generation code didn't eat our prefix.
- ServerSignature must be enabled. Print our version info.
-
- WARNING: This is a kludge!! ap_psignature() doesn't promise
- to return the empty string when ServerSignature is off. We
- know it does by code inspection, but this behavior is subject
- to change. (Perhaps we should try to get the Apache folks to
- make this promise, though. Seems harmless/useful enough...)
- */
- ap_fputs(output, bb,
- " </ul>\n <hr noshade><em>Powered by "
- "<a href=\"http://subversion.apache.org/\">"
- "Apache Subversion"
- "</a> version " SVN_VERSION "."
- "</em>\n</body></html>");
- }
- else
- ap_fputs(output, bb, " </ul>\n</body></html>");
- }
- else
- ap_fputs(output, bb, " </index>\n</svn>\n");
+ serr = emit_collection_tail(resource, bb, output, gen_html,
+ resource->pool);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "could not output collection",
+ resource->pool);
- bkt = apr_bucket_eos_create(output->c->bucket_alloc);
+ bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output));
APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS)
- return dav_svn__new_error(resource->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write EOS to filter.");
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write EOS to filter.",
+ resource->pool);
return NULL;
}
@@ -3626,10 +3762,13 @@ deliver(const dav_resource *resource, ap_filter_t *output)
"could not prepare to read a delta",
resource->pool);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
+
/* create a stream that svndiff data will be written to,
which will copy it to the network */
dc.output = output;
- dc.pool = resource->pool;
+ dc.bb = bb;
o_stream = svn_stream_create(&dc, resource->pool);
svn_stream_set_write(o_stream, write_to_filter);
svn_stream_set_close(o_stream, close_filter);
@@ -3645,6 +3784,8 @@ deliver(const dav_resource *resource, ap_filter_t *output)
to the network. */
serr = svn_txdelta_send_txstream(txd_stream, handler, h_baton,
resource->pool);
+ apr_brigade_destroy(bb);
+
if (serr != NULL)
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"could not deliver the txdelta stream",
@@ -3723,11 +3864,11 @@ deliver(const dav_resource *resource, ap_filter_t *output)
resource->info->repos->base_url,
ap_escape_uri(resource->pool,
resource->info->r->uri),
- NULL);
+ SVN_VA_NULL);
str_root = apr_pstrcat(resource->pool,
resource->info->repos->base_url,
resource->info->repos->root_path,
- NULL);
+ SVN_VA_NULL);
serr = svn_subst_build_keywords3(&kw, keywords->data,
str_cmt_rev, str_uri, str_root,
@@ -3750,13 +3891,17 @@ deliver(const dav_resource *resource, ap_filter_t *output)
### which will read from the FS stream on demand */
block = apr_palloc(resource->pool, SVN__STREAM_CHUNK_SIZE);
+ bb = apr_brigade_create(resource->pool,
+ dav_svn__output_get_bucket_alloc(output));
+
while (1) {
apr_size_t bufsize = SVN__STREAM_CHUNK_SIZE;
/* read from the FS ... */
- serr = svn_stream_read(stream, block, &bufsize);
+ serr = svn_stream_read_full(stream, block, &bufsize);
if (serr != NULL)
{
+ apr_brigade_destroy(bb);
return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"could not read the file contents",
resource->pool);
@@ -3764,30 +3909,35 @@ deliver(const dav_resource *resource, ap_filter_t *output)
if (bufsize == 0)
break;
- /* build a brigade and write to the filter ... */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
- bkt = apr_bucket_transient_create(block, bufsize,
- output->c->bucket_alloc);
+ /* write to the filter ... */
+ bkt = apr_bucket_transient_create(
+ block, bufsize, dav_svn__output_get_bucket_alloc(output));
APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) {
- /* ### what to do with status; and that HTTP code... */
- return dav_svn__new_error(resource->pool,
- HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write data to filter.");
- }
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ {
+ apr_brigade_destroy(bb);
+ /* ### that HTTP code... */
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write data to filter.",
+ resource->pool);
+ }
}
/* done with the file. write an EOS bucket now. */
- bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
- bkt = apr_bucket_eos_create(output->c->bucket_alloc);
+ bkt = apr_bucket_eos_create(dav_svn__output_get_bucket_alloc(output));
APR_BRIGADE_INSERT_TAIL(bb, bkt);
- if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) {
- /* ### what to do with status; and that HTTP code... */
- return dav_svn__new_error(resource->pool,
- HTTP_INTERNAL_SERVER_ERROR, 0,
- "Could not write EOS to filter.");
- }
+ serr = dav_svn__output_pass_brigade(output, bb);
+ if (serr != NULL)
+ {
+ apr_brigade_destroy(bb);
+ /* ### that HTTP code... */
+ return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+ "Could not write EOS to filter.",
+ resource->pool);
+ }
+ apr_brigade_destroy(bb);
return NULL;
}
}
@@ -3904,23 +4054,28 @@ copy_resource(const dav_resource *src,
return err;
}
- serr = svn_dirent_get_absolute(&src_repos_path,
- svn_repos_path(src->info->repos->repos,
- src->pool),
- src->pool);
- if (!serr)
- serr = svn_dirent_get_absolute(&dst_repos_path,
- svn_repos_path(dst->info->repos->repos,
- dst->pool),
- dst->pool);
+ src_repos_path = svn_repos_path(src->info->repos->repos, src->pool);
+ dst_repos_path = svn_repos_path(dst->info->repos->repos, dst->pool);
+
+ if (strcmp(src_repos_path, dst_repos_path) != 0)
+ {
+ /* Perhaps the source and dst repos use different path formats? */
+ serr = svn_error_compose_create(
+ svn_dirent_get_absolute(&src_repos_path, src_repos_path,
+ src->pool),
+ svn_dirent_get_absolute(&dst_repos_path, dst_repos_path,
+ dst->pool));
+
+ if (!serr && (strcmp(src_repos_path, dst_repos_path) != 0))
+ return dav_svn__new_error_svn(
+ dst->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
+ "Copy source and destination are in different repositories");
+ }
+ else
+ serr = SVN_NO_ERROR;
if (!serr)
{
- if (strcmp(src_repos_path, dst_repos_path) != 0)
- return dav_svn__new_error_tag
- (dst->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
- "Copy source and destination are in different repositories.",
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
serr = svn_fs_copy(src->info->root.root, /* root object of src rev*/
src->info->repos_path, /* relative path of src */
dst->info->root.root, /* root object of dst txn*/
@@ -4030,7 +4185,11 @@ remove_resource(dav_resource *resource, dav_response **response)
if (resource->info->version_name < created_rev)
{
serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
- "Item '%s' is out of date",
+ resource->collection
+ ? "Directory '%s' is out of date"
+ : (resource->exists
+ ? "File '%s' is out of date"
+ : "'%s' is out of date"),
resource->info->repos_path);
return dav_svn__convert_err(serr, HTTP_CONFLICT,
"Can't DELETE out-of-date resource",
@@ -4042,8 +4201,9 @@ remove_resource(dav_resource *resource, dav_response **response)
incoming lock-tokens into the filesystem's access_t. Normally
they come in via 'If:' header, and get_resource()
automatically notices them and does this work for us. In the
- case of a directory deletion, however, svn clients are sending
- 'child' lock-tokens in the DELETE request body. */
+ case of a directory deletion, however, older subversion clients
+ are sending 'child' lock-tokens in the non-standard DELETE
+ request body. */
err = dav_svn__build_lock_hash(&locks, resource->info->r,
resource->info->repos_path, resource->pool);
@@ -4157,10 +4317,15 @@ typedef struct walker_ctx_t {
} walker_ctx_t;
-
+/* Recursively walk a resource for walk(). When DEPTH != 0, recurse with
+ DEPTH-1 on child nodes. WALK_ROOT should be TRUE for the root and will be
+ FALSE for any descendants, to avoid unneeded work for every descendant
+ node.
+ */
static dav_error *
do_walk(walker_ctx_t *ctx,
int depth,
+ svn_boolean_t walk_root,
apr_pool_t *scratch_pool)
{
const dav_walk_params *params = ctx->params;
@@ -4225,16 +4390,19 @@ do_walk(walker_ctx_t *ctx,
uri_len = ctx->uri->len;
repos_len = ctx->repos_path->len;
- /* Tell our logging subsystem that we're listing a directory.
-
- Note: if we cared, we could look at the 'User-Agent:' request
- header and distinguish an svn client ('svn ls') from a generic
- DAV client. */
- dav_svn__operational_log(&ctx->info,
- svn_log__get_dir(ctx->info.repos_path,
- ctx->info.root.rev,
- TRUE, FALSE, SVN_DIRENT_ALL,
- scratch_pool));
+ if (walk_root)
+ {
+ /* Tell our logging subsystem that we're listing a directory.
+
+ Note: if we cared, we could look at the 'User-Agent:' request
+ header and distinguish an svn client ('svn ls') from a generic
+ DAV client. */
+ dav_svn__operational_log(&ctx->info,
+ svn_log__get_dir(ctx->info.repos_path,
+ ctx->info.root.rev,
+ TRUE, FALSE, SVN_DIRENT_ALL,
+ scratch_pool));
+ }
/* fetch this collection's children */
serr = svn_fs_dir_entries(&children, ctx->info.root.root,
@@ -4267,7 +4435,7 @@ do_walk(walker_ctx_t *ctx,
apr_pstrmemdup(iterpool,
ctx->repos_path->data,
ctx->repos_path->len),
- key, (char *)NULL);
+ key, SVN_VA_NULL);
if (! dav_svn__allow_read(ctx->info.r, ctx->info.repos,
repos_relpath, ctx->info.root.rev,
iterpool))
@@ -4287,7 +4455,10 @@ do_walk(walker_ctx_t *ctx,
{
err = (*params->func)(&ctx->wres, DAV_CALLTYPE_MEMBER);
if (err != NULL)
- return err;
+ {
+ svn_pool_destroy(iterpool);
+ return err;
+ }
}
else
{
@@ -4299,9 +4470,12 @@ do_walk(walker_ctx_t *ctx,
ctx->res.uri = ctx->uri->data;
/* recurse on this collection */
- err = do_walk(ctx, depth - 1, iterpool);
+ err = do_walk(ctx, depth - 1, FALSE, iterpool);
if (err != NULL)
- return err;
+ {
+ svn_pool_destroy(iterpool);
+ return err;
+ }
/* restore the data */
ctx->res.collection = FALSE;
@@ -4381,7 +4555,7 @@ walk(const dav_walk_params *params, int depth, dav_response **response)
/* ### is the root already/always open? need to verify */
/* always return the error, and any/all multistatus responses */
- err = do_walk(&ctx, depth, params->pool);
+ err = do_walk(&ctx, depth, TRUE, params->pool);
*response = ctx.wres.response;
return err;
@@ -4428,7 +4602,7 @@ dav_svn__create_working_resource(dav_resource *base,
if (base->info->repos->root_path[1])
res->uri = apr_pstrcat(base->pool, base->info->repos->root_path,
- path, (char *)NULL);
+ path, SVN_VA_NULL);
else
res->uri = path;
res->hooks = &dav_svn__hooks_repository;
@@ -4481,7 +4655,7 @@ dav_svn__working_to_regular_resource(dav_resource *resource)
/* if rev was specific, create baseline-collection URL */
path = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_BC,
priv->root.rev, priv->repos_path,
- 0, resource->pool);
+ FALSE /* add_href */, resource->pool);
}
path = svn_path_uri_encode(path, resource->pool);
priv->uri_path = svn_stringbuf_create(path, resource->pool);
@@ -4526,7 +4700,7 @@ dav_svn__create_version_resource(dav_resource **version_res,
static dav_error *
handle_post_request(request_rec *r,
dav_resource *resource,
- ap_filter_t *output)
+ dav_svn__output *output)
{
svn_skel_t *request_skel, *post_skel;
int status;
@@ -4609,7 +4783,9 @@ int dav_svn__method_post(request_rec *r)
content_type = apr_table_get(r->headers_in, "content-type");
if (content_type && (strcmp(content_type, SVN_SKEL_MIME_TYPE) == 0))
{
- derr = handle_post_request(r, resource, r->output_filters);
+ dav_svn__output *output = dav_svn__output_create(resource->info->r,
+ resource->pool);
+ derr = handle_post_request(r, resource, output);
}
else
{
diff --git a/subversion/mod_dav_svn/status.c b/subversion/mod_dav_svn/status.c
new file mode 100644
index 0000000..6dc1c9e
--- /dev/null
+++ b/subversion/mod_dav_svn/status.c
@@ -0,0 +1,115 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_config.h>
+#include <http_request.h>
+#include <http_protocol.h>
+
+#include "dav_svn.h"
+#include "private/svn_cache.h"
+#include "private/svn_fs_private.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* For getpid() */
+#endif
+
+/* The apache headers define these and they conflict with our definitions. */
+#ifdef PACKAGE_BUGREPORT
+#undef PACKAGE_BUGREPORT
+#endif
+#ifdef PACKAGE_NAME
+#undef PACKAGE_NAME
+#endif
+#ifdef PACKAGE_STRING
+#undef PACKAGE_STRING
+#endif
+#ifdef PACKAGE_TARNAME
+#undef PACKAGE_TARNAME
+#endif
+#ifdef PACKAGE_VERSION
+#undef PACKAGE_VERSION
+#endif
+#include "svn_private_config.h"
+
+#ifndef DEFAULT_TIME_FORMAT
+#define DEFAULT_TIME_FORMAT "%Y-%m-%d %H:%M:%S %Z"
+#endif
+
+/* A bit like mod_status: add a location:
+
+ <Location /svn-status>
+ SetHandler svn-status
+ </Location>
+
+ and then point a browser at http://server/svn-status.
+*/
+int dav_svn__status(request_rec *r)
+{
+ svn_cache__info_t *info;
+ svn_string_t *text_stats;
+ apr_array_header_t *lines;
+ int i;
+
+ if (r->method_number != M_GET || strcmp(r->handler, "svn-status"))
+ return DECLINED;
+
+ info = svn_cache__membuffer_get_global_info(r->pool);
+ text_stats = svn_cache__format_info(info, FALSE, r->pool);
+ lines = svn_cstring_split(text_stats->data, "\n", FALSE, r->pool);
+
+ ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+
+ ap_rvputs(r,
+ DOCTYPE_HTML_3_2
+ "<html><head>\n"
+ "<title>Apache SVN Status</title>\n"
+ "</head><body>\n"
+ "<h1>Apache SVN Cache Status for ",
+ ap_escape_html(r->pool, ap_get_server_name(r)),
+ " (via ",
+ r->connection->local_ip,
+ ")</h1>\n<dl>\n<dt>Server Version: ",
+ ap_get_server_description(),
+ "</dt>\n<dt>Current Time: ",
+ ap_ht_time(r->pool, apr_time_now(), DEFAULT_TIME_FORMAT, 0),
+ "</dt>\n", SVN_VA_NULL);
+
+#if !defined(WIN32) && defined(HAVE_UNISTD_H) && defined(HAVE_GETPID)
+ /* On Unix the server is generally multiple processes and this
+ request only shows the status of the single process that handles
+ the request. Ideally we would iterate over all processes but that
+ would need some MPM support, so we settle for simply showing the
+ process ID. */
+ ap_rprintf(r, "<dt>Server process id: %d</dt>\n", (int)getpid());
+#endif
+
+ for (i = 0; i < lines->nelts; ++i)
+ {
+ const char *line = APR_ARRAY_IDX(lines, i, const char *);
+ ap_rvputs(r, "<dt>", line, "</dt>\n", SVN_VA_NULL);
+ }
+
+ ap_rvputs(r, "</dl></body></html>\n", SVN_VA_NULL);
+
+ return 0;
+}
diff --git a/subversion/mod_dav_svn/util.c b/subversion/mod_dav_svn/util.c
index 2890502..ce824cd 100644
--- a/subversion/mod_dav_svn/util.c
+++ b/subversion/mod_dav_svn/util.c
@@ -1,5 +1,8 @@
/*
- * util.c: some handy utility functions
+ * util.c:
+ * # ****************************************************************************
+ * # TRASHY LITTLE SUBROUTINES
+ * # ****************************************************************************
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -37,7 +40,6 @@
#include "dav_svn.h"
#include "private/svn_fspath.h"
-#include "private/svn_string_private.h"
dav_error *
dav_svn__new_error(apr_pool_t *pool,
@@ -59,26 +61,24 @@ dav_svn__new_error(apr_pool_t *pool,
return dav_new_error(pool, status, error_id, 0, desc);
#else
- errno = 0; /* For the same reason as in dav_svn__new_error_tag */
+ errno = 0; /* For the same reason as in dav_svn__new_error_svn */
return dav_new_error(pool, status, error_id, desc);
#endif
}
dav_error *
-dav_svn__new_error_tag(apr_pool_t *pool,
+dav_svn__new_error_svn(apr_pool_t *pool,
int status,
int error_id,
- const char *desc,
- const char *namespace,
- const char *tagname)
+ const char *desc)
{
if (error_id == 0)
error_id = SVN_ERR_RA_DAV_REQUEST_FAILED;
#if AP_MODULE_MAGIC_AT_LEAST(20091119,0)
return dav_new_error_tag(pool, status, error_id, 0,
- desc, namespace, tagname);
+ desc, SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
#else
/* dav_new_error_tag will record errno but Subversion makes no attempt
to ensure that it is valid. We reset it to avoid putting incorrect
@@ -86,7 +86,8 @@ dav_svn__new_error_tag(apr_pool_t *pool,
valid information. */
errno = 0;
- return dav_new_error_tag(pool, status, error_id, desc, namespace, tagname);
+ return dav_new_error_tag(pool, status, error_id, desc,
+ SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
#endif
}
@@ -96,11 +97,11 @@ dav_svn__new_error_tag(apr_pool_t *pool,
static dav_error *
build_error_chain(apr_pool_t *pool, svn_error_t *err, int status)
{
- char *msg = err->message ? apr_pstrdup(pool, err->message) : NULL;
+ char buffer[128];
+ const char *msg = svn_err_best_message(err, buffer, sizeof(buffer));
- dav_error *derr = dav_svn__new_error_tag(pool, status, err->apr_err, msg,
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ dav_error *derr = dav_svn__new_error_svn(pool, status, err->apr_err,
+ apr_pstrdup(pool, msg));
if (err->child)
derr->prev = build_error_chain(pool, err->child, status);
@@ -115,51 +116,52 @@ dav_svn__convert_err(svn_error_t *serr,
const char *message,
apr_pool_t *pool)
{
- dav_error *derr;
-
- /* Remove the trace-only error chain links. We need predictable
- protocol behavior regardless of whether or not we're in a
- debugging build. */
- svn_error_t *purged_serr = svn_error_purge_tracing(serr);
-
- /* ### someday mod_dav_svn will send back 'rich' error tags, much
- finer grained than plain old svn_error_t's. But for now, all
- svn_error_t's are marshalled to the client via the single
- generic <svn:error/> tag nestled within a <D:error> block. */
-
- /* Examine the Subverion error code, and select the most
- appropriate HTTP status code. If no more appropriate HTTP
- status code maps to the Subversion error code, use the one
- suggested status provided by the caller. */
- switch (purged_serr->apr_err)
- {
- case SVN_ERR_FS_NOT_FOUND:
- status = HTTP_NOT_FOUND;
- break;
- case SVN_ERR_UNSUPPORTED_FEATURE:
- status = HTTP_NOT_IMPLEMENTED;
- break;
- case SVN_ERR_FS_LOCK_OWNER_MISMATCH:
- case SVN_ERR_FS_PATH_ALREADY_LOCKED:
- status = HTTP_LOCKED;
- break;
- case SVN_ERR_FS_PROP_BASEVALUE_MISMATCH:
- status = HTTP_PRECONDITION_FAILED;
- break;
- /* add other mappings here */
- }
-
- derr = build_error_chain(pool, purged_serr, status);
- if (message != NULL
- && purged_serr->apr_err != SVN_ERR_REPOS_HOOK_FAILURE)
- /* Don't hide hook failures; we might hide the error text */
- derr = dav_push_error(pool, status, purged_serr->apr_err,
- message, derr);
-
- /* Now, destroy the Subversion error. */
- svn_error_clear(serr);
-
- return derr;
+ dav_error *derr;
+
+ /* Remove the trace-only error chain links. We need predictable
+ protocol behavior regardless of whether or not we're in a
+ debugging build. */
+ svn_error_t *purged_serr = svn_error_purge_tracing(serr);
+
+ /* ### someday mod_dav_svn will send back 'rich' error tags, much
+ finer grained than plain old svn_error_t's. But for now, all
+ svn_error_t's are marshalled to the client via the single
+ generic <svn:error/> tag nestled within a <D:error> block. */
+
+ /* Examine the Subverion error code, and select the most
+ appropriate HTTP status code. If no more appropriate HTTP
+ status code maps to the Subversion error code, use the one
+ suggested status provided by the caller. */
+ switch (purged_serr->apr_err)
+ {
+ case SVN_ERR_FS_NOT_FOUND:
+ case SVN_ERR_FS_NO_SUCH_REVISION:
+ status = HTTP_NOT_FOUND;
+ break;
+ case SVN_ERR_UNSUPPORTED_FEATURE:
+ status = HTTP_NOT_IMPLEMENTED;
+ break;
+ case SVN_ERR_FS_LOCK_OWNER_MISMATCH:
+ case SVN_ERR_FS_PATH_ALREADY_LOCKED:
+ status = HTTP_LOCKED;
+ break;
+ case SVN_ERR_FS_PROP_BASEVALUE_MISMATCH:
+ status = HTTP_PRECONDITION_FAILED;
+ break;
+ /* add other mappings here */
+ }
+
+ derr = build_error_chain(pool, purged_serr, status);
+ if (message != NULL
+ && !svn_error_find_cause(purged_serr, SVN_ERR_REPOS_HOOK_FAILURE))
+ /* Don't hide hook failures; we might hide the error text */
+ derr = dav_push_error(pool, status, purged_serr->apr_err,
+ message, derr);
+
+ /* Now, destroy the Subversion error. */
+ svn_error_clear(serr);
+
+ return derr;
}
@@ -176,10 +178,10 @@ get_last_history_rev(svn_revnum_t *revision,
const char *ignored;
/* Get an initial HISTORY baton. */
- SVN_ERR(svn_fs_node_history(&history, root, path, pool));
+ SVN_ERR(svn_fs_node_history2(&history, root, path, pool, pool));
/* Now get the first *real* point of interesting history. */
- SVN_ERR(svn_fs_history_prev(&history, history, FALSE, pool));
+ SVN_ERR(svn_fs_history_prev2(&history, history, FALSE, pool, pool));
/* Fetch the location information for this history step. */
return svn_fs_history_location(&ignored, revision, history, pool);
@@ -193,15 +195,9 @@ dav_svn__get_safe_cr(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
svn_revnum_t history_rev;
svn_fs_root_t *other_root;
svn_fs_t *fs = svn_fs_root_fs(root);
- const svn_fs_id_t *id, *other_id;
+ svn_fs_node_relation_t node_relation;
svn_error_t *err;
- if ((err = svn_fs_node_id(&id, root, path, pool)))
- {
- svn_error_clear(err);
- return revision; /* couldn't get id of root/path */
- }
-
if ((err = get_last_history_rev(&history_rev, root, path, pool)))
{
svn_error_clear(err);
@@ -214,13 +210,14 @@ dav_svn__get_safe_cr(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
return revision; /* couldn't open the history rev */
}
- if ((err = svn_fs_node_id(&other_id, other_root, path, pool)))
+ if ((err = svn_fs_node_relation(&node_relation, root, path,
+ other_root, path, pool)))
{
svn_error_clear(err);
- return revision; /* couldn't get id of other_root/path */
+ return revision;
}
- if (svn_fs_compare_ids(id, other_id) == 0)
+ if (node_relation == svn_fs_node_unchanged)
return history_rev; /* the history rev is safe! the same node
exists at the same path in both revisions. */
@@ -234,7 +231,7 @@ dav_svn__build_uri(const dav_svn_repos *repos,
enum dav_svn__build_what what,
svn_revnum_t revision,
const char *path,
- int add_href,
+ svn_boolean_t add_href,
apr_pool_t *pool)
{
const char *root_path = repos->root_path;
@@ -464,6 +461,48 @@ dav_svn__find_ns(const apr_array_header_t *namespaces, const char *uri)
return -1;
}
+
+/*** Output helpers ***/
+
+
+struct dav_svn__output
+{
+ request_rec *r;
+};
+
+dav_svn__output *
+dav_svn__output_create(request_rec *r,
+ apr_pool_t *pool)
+{
+ dav_svn__output *output = apr_pcalloc(pool, sizeof(*output));
+ output->r = r;
+ return output;
+}
+
+apr_bucket_alloc_t *
+dav_svn__output_get_bucket_alloc(dav_svn__output *output)
+{
+ return output->r->connection->bucket_alloc;
+}
+
+svn_error_t *
+dav_svn__output_pass_brigade(dav_svn__output *output,
+ apr_bucket_brigade *bb)
+{
+ apr_status_t status;
+
+ status = ap_pass_brigade(output->r->output_filters, bb);
+ /* Empty the brigade here, as required by ap_pass_brigade(). */
+ apr_brigade_cleanup(bb);
+ if (status)
+ return svn_error_create(status, NULL, "Could not write data to filter");
+
+ /* Check for an aborted connection, since the brigade functions don't
+ appear to return useful errors when the connection is dropped. */
+ if (output->r->connection->aborted)
+ return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, NULL, NULL);
+ return SVN_NO_ERROR;
+}
/*** Brigade I/O wrappers ***/
@@ -471,17 +510,18 @@ dav_svn__find_ns(const apr_array_header_t *namespaces, const char *uri)
svn_error_t *
dav_svn__brigade_write(apr_bucket_brigade *bb,
- ap_filter_t *output,
+ dav_svn__output *output,
const char *data,
apr_size_t len)
{
apr_status_t apr_err;
- apr_err = apr_brigade_write(bb, ap_filter_flush, output, data, len);
+ apr_err = apr_brigade_write(bb, ap_filter_flush,
+ output->r->output_filters, data, len);
if (apr_err)
return svn_error_create(apr_err, 0, NULL);
/* Check for an aborted connection, since the brigade functions don't
appear to be return useful errors when the connection is dropped. */
- if (output->c->aborted)
+ if (output->r->connection->aborted)
return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL);
return SVN_NO_ERROR;
}
@@ -489,16 +529,17 @@ dav_svn__brigade_write(apr_bucket_brigade *bb,
svn_error_t *
dav_svn__brigade_puts(apr_bucket_brigade *bb,
- ap_filter_t *output,
+ dav_svn__output *output,
const char *str)
{
apr_status_t apr_err;
- apr_err = apr_brigade_puts(bb, ap_filter_flush, output, str);
+ apr_err = apr_brigade_puts(bb, ap_filter_flush,
+ output->r->output_filters, str);
if (apr_err)
return svn_error_create(apr_err, 0, NULL);
/* Check for an aborted connection, since the brigade functions don't
appear to be return useful errors when the connection is dropped. */
- if (output->c->aborted)
+ if (output->r->connection->aborted)
return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL);
return SVN_NO_ERROR;
}
@@ -506,7 +547,7 @@ dav_svn__brigade_puts(apr_bucket_brigade *bb,
svn_error_t *
dav_svn__brigade_printf(apr_bucket_brigade *bb,
- ap_filter_t *output,
+ dav_svn__output *output,
const char *fmt,
...)
{
@@ -514,18 +555,41 @@ dav_svn__brigade_printf(apr_bucket_brigade *bb,
va_list ap;
va_start(ap, fmt);
- apr_err = apr_brigade_vprintf(bb, ap_filter_flush, output, fmt, ap);
+ apr_err = apr_brigade_vprintf(bb, ap_filter_flush,
+ output->r->output_filters, fmt, ap);
va_end(ap);
if (apr_err)
return svn_error_create(apr_err, 0, NULL);
/* Check for an aborted connection, since the brigade functions don't
appear to be return useful errors when the connection is dropped. */
- if (output->c->aborted)
+ if (output->r->connection->aborted)
return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, 0, NULL);
return SVN_NO_ERROR;
}
+svn_error_t *
+dav_svn__brigade_putstrs(apr_bucket_brigade *bb,
+ dav_svn__output *output,
+ ...)
+{
+ apr_status_t apr_err;
+ va_list ap;
+
+ va_start(ap, output);
+ apr_err = apr_brigade_vputstrs(bb, ap_filter_flush,
+ output->r->output_filters, ap);
+ va_end(ap);
+ if (apr_err)
+ return svn_error_create(apr_err, NULL, NULL);
+ /* Check for an aborted connection, since the brigade functions don't
+ appear to return useful errors when the connection is dropped. */
+ if (output->r->connection->aborted)
+ return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED, NULL, NULL);
+ return SVN_NO_ERROR;
+}
+
+
dav_error *
@@ -541,12 +605,11 @@ dav_svn__test_canonical(const char *path, apr_pool_t *pool)
return NULL;
/* Otherwise, generate a generic HTTP_BAD_REQUEST error. */
- return dav_svn__new_error_tag
- (pool, HTTP_BAD_REQUEST, 0,
+ return dav_svn__new_error_svn(
+ pool, HTTP_BAD_REQUEST, 0,
apr_psprintf(pool,
"Path '%s' is not canonicalized; "
- "there is a problem with the client.", path),
- SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
+ "there is a problem with the client.", path));
}
@@ -576,18 +639,19 @@ dav_svn__sanitize_error(svn_error_t *serr,
"%s", purged_serr->message);
}
- svn_error_clear(serr);
- }
- return dav_svn__convert_err(safe_err, http_status,
- apr_psprintf(r->pool, "%s", safe_err->message),
- r->pool);
+ svn_error_clear(serr);
+ }
+
+ return dav_svn__convert_err(safe_err, http_status,
+ apr_psprintf(r->pool, "%s", safe_err->message),
+ r->pool);
}
struct brigade_write_baton
{
apr_bucket_brigade *bb;
- ap_filter_t *output;
+ dav_svn__output *output;
};
@@ -598,7 +662,8 @@ brigade_write_fn(void *baton, const char *data, apr_size_t *len)
struct brigade_write_baton *wb = baton;
apr_status_t apr_err;
- apr_err = apr_brigade_write(wb->bb, ap_filter_flush, wb->output, data, *len);
+ apr_err = apr_brigade_write(wb->bb, ap_filter_flush,
+ wb->output->r->output_filters, data, *len);
if (apr_err != APR_SUCCESS)
return svn_error_wrap_apr(apr_err, "Error writing base64 data");
@@ -609,7 +674,7 @@ brigade_write_fn(void *baton, const char *data, apr_size_t *len)
svn_stream_t *
dav_svn__make_base64_output_stream(apr_bucket_brigade *bb,
- ap_filter_t *output,
+ dav_svn__output *output,
apr_pool_t *pool)
{
struct brigade_write_baton *wb = apr_palloc(pool, sizeof(*wb));
@@ -636,7 +701,7 @@ dav_svn__operational_log(struct dav_resource_private *info, const char *line)
dav_error *
dav_svn__final_flush_or_error(request_rec *r,
apr_bucket_brigade *bb,
- ap_filter_t *output,
+ dav_svn__output *output,
dav_error *preferred_err,
apr_pool_t *pool)
{
@@ -658,7 +723,7 @@ dav_svn__final_flush_or_error(request_rec *r,
provided a more-important DERR, though. */
if (do_flush)
{
- apr_status_t apr_err = ap_fflush(output, bb);
+ apr_status_t apr_err = ap_fflush(output->r->output_filters, bb);
if (apr_err && (! derr))
derr = dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"Error flushing brigade.");
@@ -745,7 +810,7 @@ request_body_to_string(svn_string_t **request_str,
int seen_eos;
apr_status_t status;
apr_off_t total_read = 0;
- apr_off_t limit_req_body = ap_get_limit_req_body(r);
+ apr_off_t limit_req_body = ap_get_limit_xml_body(r);
int result = HTTP_BAD_REQUEST;
const char *content_length_str;
char *endp;
@@ -757,7 +822,7 @@ request_body_to_string(svn_string_t **request_str,
content_length_str = apr_table_get(r->headers_in, "Content-Length");
if (content_length_str)
{
- if (svn__strtoff(&content_length, content_length_str, &endp, 10)
+ if (apr_strtoff(&content_length, content_length_str, &endp, 10)
|| endp == content_length_str || *endp || content_length < 0)
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Invalid Content-Length");
@@ -778,7 +843,12 @@ request_body_to_string(svn_string_t **request_str,
if (content_length)
{
- buf = svn_stringbuf_create_ensure(content_length, pool);
+ /* Do not allocate more than 1 MB until we receive request body. */
+ apr_size_t alloc_len = 1 * 1024 *1024;
+ if (content_length < alloc_len)
+ alloc_len = (apr_size_t) content_length;
+
+ buf = svn_stringbuf_create_ensure(alloc_len, pool);
}
else
{
@@ -861,7 +931,7 @@ dav_svn__parse_request_skel(svn_skel_t **skel,
*skel = NULL;
status = request_body_to_string(&skel_str, r, pool);
if (status != OK)
- return OK;
+ return status;
*skel = svn_skel__parse(skel_str->data, skel_str->len, pool);
return OK;
diff --git a/subversion/mod_dav_svn/version.c b/subversion/mod_dav_svn/version.c
index 98208a9..638cae9 100644
--- a/subversion/mod_dav_svn/version.c
+++ b/subversion/mod_dav_svn/version.c
@@ -178,26 +178,33 @@ get_option(const dav_resource *resource,
request_rec *r = resource->info->r;
const char *repos_root_uri =
dav_svn__build_uri(resource->info->repos, DAV_SVN__BUILD_URI_PUBLIC,
- SVN_IGNORED_REVNUM, "", 0, resource->pool);
+ SVN_IGNORED_REVNUM, "", FALSE /* add_href */,
+ resource->pool);
/* ### DAV:version-history-collection-set */
- if (elem->ns == APR_XML_NS_DAV_ID)
+ if (elem->ns != APR_XML_NS_DAV_ID
+ || strcmp(elem->name, "activity-collection-set") != 0)
{
- if (strcmp(elem->name, "activity-collection-set") == 0)
- {
- apr_text_append(resource->pool, option,
- "<D:activity-collection-set>");
- apr_text_append(resource->pool, option,
- dav_svn__build_uri(resource->info->repos,
- DAV_SVN__BUILD_URI_ACT_COLLECTION,
- SVN_INVALID_REVNUM, NULL,
- 1 /* add_href */,
- resource->pool));
- apr_text_append(resource->pool, option,
- "</D:activity-collection-set>");
- }
+ /* We don't know about other options (yet).
+
+ If we ever add multiple option request keys we should
+ just write the requested option value and make sure
+ we set the headers *once*. */
+ return NULL;
}
+ apr_text_append(resource->pool, option,
+ "<D:activity-collection-set>");
+
+ apr_text_append(resource->pool, option,
+ dav_svn__build_uri(resource->info->repos,
+ DAV_SVN__BUILD_URI_ACT_COLLECTION,
+ SVN_INVALID_REVNUM, NULL,
+ TRUE /* add_href */,
+ resource->pool));
+ apr_text_append(resource->pool, option,
+ "</D:activity-collection-set>");
+
/* If we're allowed (by configuration) to do so, advertise support
for ephemeral transaction properties. */
if (dav_svn__check_ephemeral_txnprops_support(r))
@@ -297,25 +304,25 @@ get_option(const dav_resource *resource,
apr_table_set(r->headers_out, SVN_DAV_ROOT_URI_HEADER, repos_root_uri);
apr_table_set(r->headers_out, SVN_DAV_ME_RESOURCE_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_me_resource_uri(r), (char *)NULL));
+ dav_svn__get_me_resource_uri(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_REV_ROOT_STUB_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_rev_root_stub(r), (char *)NULL));
+ dav_svn__get_rev_root_stub(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_REV_STUB_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_rev_stub(r), (char *)NULL));
+ dav_svn__get_rev_stub(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_TXN_ROOT_STUB_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_txn_root_stub(r), (char *)NULL));
+ dav_svn__get_txn_root_stub(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_TXN_STUB_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_txn_stub(r), (char *)NULL));
+ dav_svn__get_txn_stub(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_VTXN_ROOT_STUB_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_vtxn_root_stub(r), (char *)NULL));
+ dav_svn__get_vtxn_root_stub(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_VTXN_STUB_HEADER,
apr_pstrcat(resource->pool, repos_root_uri, "/",
- dav_svn__get_vtxn_stub(r), (char *)NULL));
+ dav_svn__get_vtxn_stub(r), SVN_VA_NULL));
apr_table_set(r->headers_out, SVN_DAV_ALLOW_BULK_UPDATES,
bulk_upd_conf == CONF_BULKUPD_ON ? "On" :
bulk_upd_conf == CONF_BULKUPD_OFF ? "Off" : "Prefer");
@@ -395,11 +402,9 @@ vsn_control(dav_resource *resource, const char *target)
/* Only allow a NULL target, which means an create an 'empty' VCR. */
if (target != NULL)
- return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED,
SVN_ERR_UNSUPPORTED_FEATURE,
- "vsn_control called with non-null target.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "vsn_control called with non-null target");
/* This is kind of silly. The docstring for this callback says it's
supposed to "put a resource under version control". But in
@@ -445,20 +450,16 @@ dav_svn__checkout(dav_resource *resource,
return NULL;
if (resource->type != DAV_RESOURCE_TYPE_REGULAR)
- return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_METHOD_NOT_ALLOWED,
SVN_ERR_UNSUPPORTED_FEATURE,
"auto-checkout attempted on non-regular "
- "version-controlled resource.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "version-controlled resource");
if (resource->baselined)
- return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_METHOD_NOT_ALLOWED,
SVN_ERR_UNSUPPORTED_FEATURE,
"auto-checkout attempted on baseline "
- "collection, which is not supported.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "collection, which is not supported");
/* See if the shared activity already exists. */
apr_err = apr_pool_userdata_get(&data,
@@ -540,51 +541,41 @@ dav_svn__checkout(dav_resource *resource,
if (resource->type != DAV_RESOURCE_TYPE_VERSION)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_METHOD_NOT_ALLOWED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_METHOD_NOT_ALLOWED,
SVN_ERR_UNSUPPORTED_FEATURE,
"CHECKOUT can only be performed on a "
- "version resource [at this time].",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "version resource");
}
if (create_activity)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED,
SVN_ERR_UNSUPPORTED_FEATURE,
"CHECKOUT cannot create an activity at "
- "this time. Use MKACTIVITY first.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "this time. Use MKACTIVITY first");
}
if (is_unreserved)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED,
SVN_ERR_UNSUPPORTED_FEATURE,
"Unreserved checkouts are not yet "
"available. A version history may not be "
"checked out more than once, into a "
- "specific activity.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "specific activity");
}
if (activities == NULL)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT,
+ return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT,
SVN_ERR_INCOMPLETE_DATA,
"An activity must be provided for "
- "checkout.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "checkout");
}
/* assert: nelts > 0. the below check effectively means > 1. */
if (activities->nelts != 1)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT,
+ return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT,
SVN_ERR_INCORRECT_PARAMS,
"Only one activity may be specified within "
- "the CHECKOUT.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "the CHECKOUT");
}
serr = dav_svn__simple_parse_uri(&parse, resource,
@@ -600,21 +591,17 @@ dav_svn__checkout(dav_resource *resource,
}
if (parse.activity_id == NULL)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT,
+ return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT,
SVN_ERR_INCORRECT_PARAMS,
- "The provided href is not an activity URI.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "The provided href is not an activity URI");
}
if ((txn_name = dav_svn__get_txn(resource->info->repos,
parse.activity_id)) == NULL)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT,
+ return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT,
SVN_ERR_APMOD_ACTIVITY_NOT_FOUND,
- "The specified activity does not exist.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "The specified activity does not exist");
}
/* verify the specified version resource is the "latest", thus allowing
@@ -642,13 +629,11 @@ dav_svn__checkout(dav_resource *resource,
if (resource->info->root.rev != youngest)
{
- return dav_svn__new_error_tag(resource->pool, HTTP_CONFLICT,
+ return dav_svn__new_error_svn(resource->pool, HTTP_CONFLICT,
SVN_ERR_APMOD_BAD_BASELINE,
"The specified baseline is not the "
"latest baseline, so it may not be "
- "checked out.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "checked out");
}
/* ### hmm. what if the transaction root's revision is different
@@ -742,11 +727,9 @@ dav_svn__checkout(dav_resource *resource,
{
/* The item being modified is older than the one in the
transaction. The client is out of date. */
- return dav_svn__new_error_tag
+ return dav_svn__new_error_svn
(resource->pool, HTTP_CONFLICT, SVN_ERR_FS_CONFLICT,
- "resource out of date; try updating",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "resource out of date; try updating");
}
else if (resource->info->root.rev > txn_created_rev)
{
@@ -754,42 +737,25 @@ dav_svn__checkout(dav_resource *resource,
revision than the one in the transaction. We'll
check to see if they are still the same node, and if
not, return an error. */
- const svn_fs_id_t *url_noderev_id, *txn_noderev_id;
-
- if ((serr = svn_fs_node_id(&txn_noderev_id, txn_root,
- resource->info->repos_path,
- resource->pool)))
+ svn_fs_node_relation_t node_relation;
+ if ((serr = svn_fs_node_relation(&node_relation, txn_root,
+ resource->info->repos_path,
+ resource->info->root.root,
+ resource->info->repos_path,
+ resource->pool)))
{
- err = dav_svn__new_error_tag
+ err = dav_svn__new_error_svn
(resource->pool, HTTP_CONFLICT, serr->apr_err,
"Unable to fetch the node revision id of the version "
- "resource within the transaction.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "resource within the revision");
svn_error_clear(serr);
return err;
}
- if ((serr = svn_fs_node_id(&url_noderev_id,
- resource->info->root.root,
- resource->info->repos_path,
- resource->pool)))
+ if (node_relation != svn_fs_node_unchanged)
{
- err = dav_svn__new_error_tag
- (resource->pool, HTTP_CONFLICT, serr->apr_err,
- "Unable to fetch the node revision id of the version "
- "resource within the revision.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
- svn_error_clear(serr);
- return err;
- }
- if (svn_fs_compare_ids(url_noderev_id, txn_noderev_id) != 0)
- {
- return dav_svn__new_error_tag
+ return dav_svn__new_error_svn
(resource->pool, HTTP_CONFLICT, SVN_ERR_FS_CONFLICT,
- "version resource newer than txn (restart the commit)",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "version resource newer than txn (restart the commit)");
}
}
}
@@ -806,11 +772,9 @@ static dav_error *
uncheckout(dav_resource *resource)
{
if (resource->type != DAV_RESOURCE_TYPE_WORKING)
- return dav_svn__new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR,
+ return dav_svn__new_error_svn(resource->pool, HTTP_INTERNAL_SERVER_ERROR,
SVN_ERR_UNSUPPORTED_FEATURE,
- "UNCHECKOUT called on non-working resource.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "UNCHECKOUT called on non-working resource");
/* Try to abort the txn if it exists; but don't try too hard. :-) */
if (resource->info->root.txn)
@@ -877,7 +841,7 @@ cleanup_deltify(void *data)
subpool, then destroy it before exiting. */
apr_pool_t *subpool = svn_pool_create(cdb->pool);
- err = svn_repos_open2(&repos, cdb->repos_path, NULL, subpool);
+ err = svn_repos_open3(&repos, cdb->repos_path, NULL, subpool, subpool);
if (err)
{
ap_log_perror(APLOG_MARK, APLOG_ERR, err->apr_err, cdb->pool,
@@ -949,11 +913,9 @@ dav_svn__checkin(dav_resource *resource,
txn? Many txns? Etc.) */
if (resource->type != DAV_RESOURCE_TYPE_WORKING)
- return dav_svn__new_error_tag(resource->pool, HTTP_INTERNAL_SERVER_ERROR,
+ return dav_svn__new_error_svn(resource->pool, HTTP_INTERNAL_SERVER_ERROR,
SVN_ERR_UNSUPPORTED_FEATURE,
- "CHECKIN called on non-working resource.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "CHECKIN called on non-working resource");
/* If the global autoversioning activity still exists, that means
nobody's committed it yet. */
@@ -1010,7 +972,7 @@ dav_svn__checkin(dav_resource *resource,
{
const char *post_commit_err = svn_repos__post_commit_error_str
(serr, resource->pool);
- ap_log_perror(APLOG_MARK, APLOG_ERR, serr->apr_err,
+ ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL,
resource->pool,
"commit of r%ld succeeded, but an error occurred "
"after the commit: '%s'",
@@ -1079,7 +1041,7 @@ dav_svn__checkin(dav_resource *resource,
uri = dav_svn__build_uri(resource->info->repos,
DAV_SVN__BUILD_URI_VERSION,
new_rev, resource->info->repos_path,
- 0, resource->pool);
+ FALSE /* add_href */, resource->pool);
err = dav_svn__create_version_resource(version_resource, uri,
resource->pool);
@@ -1130,12 +1092,16 @@ static dav_error *
deliver_report(request_rec *r,
const dav_resource *resource,
const apr_xml_doc *doc,
- ap_filter_t *output)
+ ap_filter_t *unused)
{
int ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (doc->root->ns == ns)
{
+ dav_svn__output *output;
+
+ output = dav_svn__output_create(resource->info->r, resource->pool);
+
/* ### note that these report names should have symbols... */
if (strcmp(doc->root->name, "update-report") == 0)
@@ -1188,11 +1154,9 @@ deliver_report(request_rec *r,
}
/* ### what is a good error for an unknown report? */
- return dav_svn__new_error_tag(resource->pool, HTTP_NOT_IMPLEMENTED,
+ return dav_svn__new_error_svn(resource->pool, HTTP_NOT_IMPLEMENTED,
SVN_ERR_UNSUPPORTED_FEATURE,
- "The requested report is unknown.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "The requested report is unknown");
}
@@ -1219,13 +1183,11 @@ make_activity(dav_resource *resource)
/* sanity check: make sure the resource is a valid activity, in
case an older mod_dav doesn't do the check for us. */
if (! can_be_activity(resource))
- return dav_svn__new_error_tag(resource->pool, HTTP_FORBIDDEN,
+ return dav_svn__new_error_svn(resource->pool, HTTP_FORBIDDEN,
SVN_ERR_APMOD_MALFORMED_URI,
"Activities cannot be created at that "
"location; query the "
- "DAV:activity-collection-set property.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "DAV:activity-collection-set property");
err = dav_svn__create_txn(resource->info->repos, &txn_name,
NULL, resource->pool);
@@ -1396,6 +1358,23 @@ dav_svn__push_locks(dav_resource *resource,
return NULL;
}
+/* Implements svn_fs_lock_callback_t. */
+static svn_error_t *
+unlock_many_cb(void *lock_baton,
+ const char *path,
+ const svn_lock_t *lock,
+ svn_error_t *fs_err,
+ apr_pool_t *pool)
+{
+ request_rec *r = lock_baton;
+
+ if (fs_err)
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, fs_err->apr_err, r,
+ "%s", fs_err->message);
+
+ return SVN_NO_ERROR;
+}
+
/* Helper for merge(). Free every lock in LOCKS. The locks
live in REPOS. Log any errors for REQUEST. Use POOL for temporary
@@ -1406,28 +1385,16 @@ release_locks(apr_hash_t *locks,
request_rec *r,
apr_pool_t *pool)
{
- apr_hash_index_t *hi;
- const void *key;
- void *val;
apr_pool_t *subpool = svn_pool_create(pool);
svn_error_t *err;
- for (hi = apr_hash_first(pool, locks); hi; hi = apr_hash_next(hi))
- {
- svn_pool_clear(subpool);
- apr_hash_this(hi, &key, NULL, &val);
-
- /* The lock may be stolen or broken sometime between
- svn_fs_commit_txn() and this post-commit cleanup. So ignore
- any errors from this command; just free as many locks as we can. */
- err = svn_repos_fs_unlock(repos, key, val, FALSE, subpool);
+ err = svn_repos_fs_unlock_many(repos, locks, FALSE, unlock_many_cb, r,
+ subpool, subpool);
- if (err) /* If we got an error, just log it and move along. */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, err->apr_err, r,
- "%s", err->message);
-
- svn_error_clear(err);
- }
+ if (err) /* If we got an error, just log it and move along. */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, err->apr_err, r,
+ "%s", err->message);
+ svn_error_clear(err);
svn_pool_destroy(subpool);
@@ -1441,7 +1408,7 @@ merge(dav_resource *target,
int no_auto_merge,
int no_checkout,
apr_xml_elem *prop_elem,
- ap_filter_t *output)
+ ap_filter_t *unused)
{
apr_pool_t *pool;
dav_error *err;
@@ -1452,6 +1419,7 @@ merge(dav_resource *target,
svn_revnum_t new_rev;
apr_hash_t *locks;
svn_boolean_t disable_merge_response = FALSE;
+ dav_svn__output *output;
/* We'll use the target's pool for our operation. We happen to know that
it matches the request pool, which (should) have the proper lifetime. */
@@ -1464,22 +1432,18 @@ merge(dav_resource *target,
|| (source->type == DAV_RESOURCE_TYPE_PRIVATE
&& source->info->restype == DAV_SVN_RESTYPE_TXN_COLLECTION)))
{
- return dav_svn__new_error_tag(pool, HTTP_METHOD_NOT_ALLOWED,
+ return dav_svn__new_error_svn(pool, HTTP_METHOD_NOT_ALLOWED,
SVN_ERR_INCORRECT_PARAMS,
"MERGE can only be performed using an "
"activity or transaction resource as the "
- "source.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "source");
}
if (! source->exists)
{
- return dav_svn__new_error_tag(pool, HTTP_METHOD_NOT_ALLOWED,
+ return dav_svn__new_error_svn(pool, HTTP_METHOD_NOT_ALLOWED,
SVN_ERR_INCORRECT_PARAMS,
"MERGE activity or transaction resource "
- "does not exist.",
- SVN_DAV_ERROR_NAMESPACE,
- SVN_DAV_ERROR_TAG);
+ "does not exist");
}
/* Before attempting the final commit, we need to push any incoming
@@ -1528,6 +1492,11 @@ merge(dav_resource *target,
### client some other way than hijacking the post-commit
### error message.*/
post_commit_err = svn_repos__post_commit_error_str(serr, pool);
+ ap_log_perror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, pool,
+ "commit of r%ld succeeded, but an error occurred "
+ "after the commit: '%s'",
+ new_rev,
+ post_commit_err);
svn_error_clear(serr);
serr = SVN_NO_ERROR;
}
@@ -1620,6 +1589,7 @@ merge(dav_resource *target,
}
/* process the response for the new revision. */
+ output = dav_svn__output_create(target->info->r, pool);
return dav_svn__merge_response(output, source->info->repos, new_rev,
post_commit_err, prop_elem,
disable_merge_response, pool);