diff options
author | Peter Wemm <peter@FreeBSD.org> | 2014-08-11 19:19:17 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2014-08-11 19:19:17 +0000 |
commit | 6f0665939667af9f780762878fc35982e8b7d745 (patch) | |
tree | 7641ccc1b31a300b13c0cfcf8ab6c33e17646de1 /subversion/libsvn_ra_serf | |
parent | 41a48a0a1803245a188068c5200383b9543c25b2 (diff) |
Notes
Diffstat (limited to 'subversion/libsvn_ra_serf')
-rw-r--r-- | subversion/libsvn_ra_serf/commit.c | 185 | ||||
-rw-r--r-- | subversion/libsvn_ra_serf/options.c | 2 | ||||
-rw-r--r-- | subversion/libsvn_ra_serf/util.c | 57 |
3 files changed, 147 insertions, 97 deletions
diff --git a/subversion/libsvn_ra_serf/commit.c b/subversion/libsvn_ra_serf/commit.c index 4950ac48911ae..1f9f1cc99f065 100644 --- a/subversion/libsvn_ra_serf/commit.c +++ b/subversion/libsvn_ra_serf/commit.c @@ -99,14 +99,11 @@ typedef struct proppatch_context_t { } proppatch_context_t; typedef struct delete_context_t { - const char *path; + const char *relpath; svn_revnum_t revision; - const char *lock_token; - apr_hash_t *lock_token_hash; - svn_boolean_t keep_locks; - + commit_context_t *commit; } delete_context_t; /* Represents a directory. */ @@ -149,7 +146,6 @@ typedef struct dir_context_t { /* The checked-out working resource for this directory. May be NULL; if so call checkout_dir() first. */ const char *working_url; - } dir_context_t; /* Represents a file to be committed. */ @@ -1078,6 +1074,96 @@ setup_copy_file_headers(serf_bucket_t *headers, } static svn_error_t * +setup_if_header_recursive(svn_boolean_t *added, + serf_bucket_t *headers, + commit_context_t *commit_ctx, + const char *rq_relpath, + apr_pool_t *pool) +{ + svn_stringbuf_t *sb = NULL; + apr_hash_index_t *hi; + apr_pool_t *iterpool = NULL; + + if (!commit_ctx->lock_tokens) + { + *added = FALSE; + return SVN_NO_ERROR; + } + + /* We try to create a directory, so within the Subversion world that + would imply that there is nothing here, but mod_dav_svn still sees + locks on the old nodes here as in DAV it is perfectly legal to lock + something that is not there... + + Let's make mod_dav, mod_dav_svn and the DAV RFC happy by providing + the locks we know of with the request */ + + for (hi = apr_hash_first(pool, commit_ctx->lock_tokens); + hi; + hi = apr_hash_next(hi)) + { + const char *relpath = svn__apr_hash_index_key(hi); + apr_uri_t uri; + + if (!svn_relpath_skip_ancestor(rq_relpath, relpath)) + continue; + else if (svn_hash_gets(commit_ctx->deleted_entries, relpath)) + { + /* When a path is already explicit deleted then its lock + will be removed by mod_dav. But mod_dav doesn't remove + locks on descendants */ + continue; + } + + if (!iterpool) + iterpool = svn_pool_create(pool); + else + svn_pool_clear(iterpool); + + if (sb == NULL) + sb = svn_stringbuf_create("", pool); + else + svn_stringbuf_appendbyte(sb, ' '); + + uri = commit_ctx->session->session_url; + uri.path = (char *)svn_path_url_add_component2(uri.path, relpath, + iterpool); + + svn_stringbuf_appendbyte(sb, '<'); + svn_stringbuf_appendcstr(sb, apr_uri_unparse(iterpool, &uri, 0)); + svn_stringbuf_appendcstr(sb, "> (<"); + svn_stringbuf_appendcstr(sb, svn__apr_hash_index_val(hi)); + svn_stringbuf_appendcstr(sb, ">)"); + } + + if (iterpool) + svn_pool_destroy(iterpool); + + if (sb) + { + serf_bucket_headers_set(headers, "If", sb->data); + *added = TRUE; + } + else + *added = FALSE; + + return SVN_NO_ERROR; +} + +static svn_error_t * +setup_add_dir_common_headers(serf_bucket_t *headers, + void *baton, + apr_pool_t *pool) +{ + dir_context_t *dir = baton; + svn_boolean_t added; + + return svn_error_trace( + setup_if_header_recursive(&added, headers, dir->commit, dir->relpath, + pool)); +} + +static svn_error_t * setup_copy_dir_headers(serf_bucket_t *headers, void *baton, apr_pool_t *pool) @@ -1109,7 +1195,7 @@ setup_copy_dir_headers(serf_bucket_t *headers, /* Implicitly checkout this dir now. */ dir->working_url = apr_pstrdup(dir->pool, uri.path); - return SVN_NO_ERROR; + return svn_error_trace(setup_add_dir_common_headers(headers, baton, pool)); } static svn_error_t * @@ -1117,54 +1203,22 @@ setup_delete_headers(serf_bucket_t *headers, void *baton, apr_pool_t *pool) { - delete_context_t *ctx = baton; + delete_context_t *del = baton; + svn_boolean_t added; serf_bucket_headers_set(headers, SVN_DAV_VERSION_NAME_HEADER, - apr_ltoa(pool, ctx->revision)); + apr_ltoa(pool, del->revision)); - if (ctx->lock_token_hash) - { - ctx->lock_token = svn_hash_gets(ctx->lock_token_hash, ctx->path); + SVN_ERR(setup_if_header_recursive(&added, headers, del->commit, + del->relpath, pool)); - if (ctx->lock_token) - { - const char *token_header; - - token_header = apr_pstrcat(pool, "<", ctx->path, "> (<", - ctx->lock_token, ">)", (char *)NULL); - - serf_bucket_headers_set(headers, "If", token_header); - - if (ctx->keep_locks) - serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER, - SVN_DAV_OPTION_KEEP_LOCKS); - } - } + if (added && del->commit->keep_locks) + serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER, + SVN_DAV_OPTION_KEEP_LOCKS); return SVN_NO_ERROR; } -/* Implements svn_ra_serf__request_body_delegate_t */ -static svn_error_t * -create_delete_body(serf_bucket_t **body_bkt, - void *baton, - serf_bucket_alloc_t *alloc, - apr_pool_t *pool) -{ - delete_context_t *ctx = baton; - serf_bucket_t *body; - - body = serf_bucket_aggregate_create(alloc); - - svn_ra_serf__add_xml_header_buckets(body, alloc); - - svn_ra_serf__merge_lock_token_list(ctx->lock_token_hash, ctx->path, - body, alloc, pool); - - *body_bkt = body; - return SVN_NO_ERROR; -} - /* Helper function to write the svndiff stream to temporary file. */ static svn_error_t * svndiff_stream_write(void *file_baton, @@ -1541,7 +1595,6 @@ delete_entry(const char *path, delete_context_t *delete_ctx; svn_ra_serf__handler_t *handler; const char *delete_target; - svn_error_t *err; if (USING_HTTPV2_COMMIT_SUPPORT(dir->commit)) { @@ -1560,10 +1613,9 @@ delete_entry(const char *path, /* DELETE our entry */ delete_ctx = apr_pcalloc(pool, sizeof(*delete_ctx)); - delete_ctx->path = apr_pstrdup(pool, path); + delete_ctx->relpath = apr_pstrdup(pool, path); delete_ctx->revision = revision; - delete_ctx->lock_token_hash = dir->commit->lock_tokens; - delete_ctx->keep_locks = dir->commit->keep_locks; + delete_ctx->commit = dir->commit; handler = apr_pcalloc(pool, sizeof(*handler)); handler->handler_pool = pool; @@ -1579,30 +1631,7 @@ delete_entry(const char *path, handler->method = "DELETE"; handler->path = delete_target; - err = svn_ra_serf__context_run_one(handler, pool); - - if (err && - (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN || - err->apr_err == SVN_ERR_FS_NO_LOCK_TOKEN || - err->apr_err == SVN_ERR_FS_LOCK_OWNER_MISMATCH || - err->apr_err == SVN_ERR_FS_PATH_ALREADY_LOCKED)) - { - svn_error_clear(err); - - /* An error has been registered on the connection. Reset the thing - so that we can use it again. */ - serf_connection_reset(handler->conn->conn); - - handler->body_delegate = create_delete_body; - handler->body_delegate_baton = delete_ctx; - handler->body_type = "text/xml"; - - SVN_ERR(svn_ra_serf__context_run_one(handler, pool)); - } - else if (err) - { - return err; - } + SVN_ERR(svn_ra_serf__context_run_one(handler, pool)); /* 204 No Content: item successfully deleted */ if (handler->sline.code != 204) @@ -1673,6 +1702,9 @@ add_directory(const char *path, { handler->method = "MKCOL"; handler->path = mkcol_target; + + handler->header_delegate = setup_add_dir_common_headers; + handler->header_delegate_baton = dir; } else { @@ -2341,7 +2373,8 @@ svn_ra_serf__get_commit_editor(svn_ra_session_t *ra_session, ctx->callback = callback; ctx->callback_baton = callback_baton; - ctx->lock_tokens = lock_tokens; + ctx->lock_tokens = (lock_tokens && apr_hash_count(lock_tokens)) + ? lock_tokens : NULL; ctx->keep_locks = keep_locks; ctx->deleted_entries = apr_hash_make(ctx->pool); diff --git a/subversion/libsvn_ra_serf/options.c b/subversion/libsvn_ra_serf/options.c index a3c2fb95c8811..f61ee87142c62 100644 --- a/subversion/libsvn_ra_serf/options.c +++ b/subversion/libsvn_ra_serf/options.c @@ -302,7 +302,7 @@ capabilities_headers_iterator_callback(void *baton, /* May contain multiple values, separated by commas. */ int i; apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE, - opt_ctx->pool); + session->pool); for (i = 0; i < vals->nelts; i++) { diff --git a/subversion/libsvn_ra_serf/util.c b/subversion/libsvn_ra_serf/util.c index 60fa3c44af178..8f6c1bb5d4fac 100644 --- a/subversion/libsvn_ra_serf/util.c +++ b/subversion/libsvn_ra_serf/util.c @@ -28,7 +28,6 @@ #define APR_WANT_STRFUNC #include <apr.h> #include <apr_want.h> -#include <apr_fnmatch.h> #include <serf.h> #include <serf_bucket_types.h> @@ -49,6 +48,7 @@ #include "private/svn_fspath.h" #include "private/svn_subr_private.h" #include "private/svn_auth_private.h" +#include "private/svn_cert.h" #include "ra_serf.h" @@ -274,7 +274,6 @@ ssl_server_cert(void *baton, int failures, apr_hash_t *subject = NULL; apr_hash_t *serf_cert = NULL; void *creds; - int found_matching_hostname = 0; svn_failures = (ssl_convert_serf_failures(failures) | conn->server_cert_failures); @@ -286,26 +285,37 @@ ssl_server_cert(void *baton, int failures, ### This should really be handled by serf, which should pass an error for this case, but that has backwards compatibility issues. */ apr_array_header_t *san; + svn_boolean_t found_san_entry = FALSE; + svn_boolean_t found_matching_hostname = FALSE; + svn_string_t *actual_hostname = + svn_string_create(conn->session->session_url.hostname, scratch_pool); serf_cert = serf_ssl_cert_certificate(cert, scratch_pool); san = svn_hash_gets(serf_cert, "subjectAltName"); /* Try to find matching server name via subjectAltName first... */ - if (san) { + if (san) + { int i; - for (i = 0; i < san->nelts; i++) { + found_san_entry = san->nelts > 0; + for (i = 0; i < san->nelts; i++) + { const char *s = APR_ARRAY_IDX(san, i, const char*); - if (apr_fnmatch(s, conn->session->session_url.hostname, - APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS) - { - found_matching_hostname = 1; + svn_string_t *cert_hostname = svn_string_create(s, scratch_pool); + + if (svn_cert__match_dns_identity(cert_hostname, actual_hostname)) + { + found_matching_hostname = TRUE; break; - } - } - } + } + } + } - /* Match server certificate CN with the hostname of the server */ - if (!found_matching_hostname) + /* Match server certificate CN with the hostname of the server iff + * we didn't find any subjectAltName fields and try to match them. + * Per RFC 2818 they are authoritative if present and CommonName + * should be ignored. */ + if (!found_matching_hostname && !found_san_entry) { const char *hostname = NULL; @@ -314,13 +324,20 @@ ssl_server_cert(void *baton, int failures, if (subject) hostname = svn_hash_gets(subject, "CN"); - if (!hostname - || apr_fnmatch(hostname, conn->session->session_url.hostname, - APR_FNM_PERIOD | APR_FNM_CASE_BLIND) != APR_SUCCESS) - { - svn_failures |= SVN_AUTH_SSL_CNMISMATCH; - } - } + if (hostname) + { + svn_string_t *cert_hostname = svn_string_create(hostname, + scratch_pool); + + if (svn_cert__match_dns_identity(cert_hostname, actual_hostname)) + { + found_matching_hostname = TRUE; + } + } + } + + if (!found_matching_hostname) + svn_failures |= SVN_AUTH_SSL_CNMISMATCH; } if (!svn_failures) |