diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/mod_dav_svn/util.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/mod_dav_svn/util.c')
-rw-r--r-- | subversion/mod_dav_svn/util.c | 266 |
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; |