summaryrefslogtreecommitdiff
path: root/subversion/mod_dav_svn/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/mod_dav_svn/util.c')
-rw-r--r--subversion/mod_dav_svn/util.c266
1 files changed, 168 insertions, 98 deletions
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;