int svn_cstring_casecmp(const char *str1, const char *str2) { for (;;) { const int a = *str1++; const int b = *str2++; const int cmp = svn_ctype_casecmp(a, b); if (cmp || !a || !b) return cmp; } }
/* This implements serf_bucket_headers_do_callback_fn_t. */ static int capabilities_headers_iterator_callback(void *baton, const char *key, const char *val) { options_context_t *opt_ctx = baton; svn_ra_serf__session_t *session = opt_ctx->session; if (svn_cstring_casecmp(key, "dav") == 0) { /* Each header may contain multiple values, separated by commas, e.g.: DAV: version-control,checkout,working-resource DAV: merge,baseline,activity,version-controlled-collection DAV: http://subversion.tigris.org/xmlns/dav/svn/depth */ apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE, opt_ctx->pool); opt_ctx->received_dav_header = TRUE; /* Right now we only have a few capabilities to detect, so just seek for them directly. This could be written slightly more efficiently, but that wouldn't be worth it until we have many more capabilities. */ if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_DEPTH, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_MERGEINFO, vals)) { /* The server doesn't know what repository we're referring to, so it can't just say capability_yes. */ if (!svn_hash_gets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO, capability_server_yes); } } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_LOG_REVPROPS, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INHERITED_PROPS, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_INHERITED_PROPS, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_REVERSE_FILE_REVS, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INLINE_PROPS, vals)) { session->supports_inline_props = TRUE; } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_REPLAY_REV_RESOURCE, vals)) { session->supports_rev_rsrc_replay = TRUE; } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_SVNDIFF1, vals)) { /* Use compressed svndiff1 format for servers that properly advertise this capability (Subversion 1.10 and greater). */ session->supports_svndiff1 = TRUE; } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_LIST, vals)) { svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_LIST, capability_yes); } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_SVNDIFF2, vals)) { /* Same for svndiff2. */ session->supports_svndiff2 = TRUE; } if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PUT_RESULT_CHECKSUM, vals)) { session->supports_put_result_checksum = TRUE; } } /* SVN-specific headers -- if present, server supports HTTP protocol v2 */ else if (!svn_ctype_casecmp(key[0], 'S') && !svn_ctype_casecmp(key[1], 'V') && !svn_ctype_casecmp(key[2], 'N')) { /* If we've not yet seen any information about supported POST requests, we'll initialize the list/hash with "create-txn" (which we know is supported by virtue of the server speaking HTTPv2 at all. */ if (! session->supported_posts) { session->supported_posts = apr_hash_make(session->pool); apr_hash_set(session->supported_posts, "create-txn", 10, (void *)1); } if (svn_cstring_casecmp(key, SVN_DAV_ROOT_URI_HEADER) == 0) { session->repos_root = session->session_url; session->repos_root.path = (char *)svn_fspath__canonicalize(val, session->pool); session->repos_root_str = svn_urlpath__canonicalize( apr_uri_unparse(session->pool, &session->repos_root, 0), session->pool); } else if (svn_cstring_casecmp(key, SVN_DAV_ME_RESOURCE_HEADER) == 0) { #ifdef SVN_DEBUG char *ignore_v2_env_var = getenv(SVN_IGNORE_V2_ENV_VAR); if (!(ignore_v2_env_var && apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0)) session->me_resource = apr_pstrdup(session->pool, val); #else session->me_resource = apr_pstrdup(session->pool, val); #endif } else if (svn_cstring_casecmp(key, SVN_DAV_REV_STUB_HEADER) == 0) { session->rev_stub = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_REV_ROOT_STUB_HEADER) == 0) { session->rev_root_stub = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_TXN_STUB_HEADER) == 0) { session->txn_stub = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_TXN_ROOT_STUB_HEADER) == 0) { session->txn_root_stub = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_STUB_HEADER) == 0) { session->vtxn_stub = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_ROOT_STUB_HEADER) == 0) { session->vtxn_root_stub = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_REPOS_UUID_HEADER) == 0) { session->uuid = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_YOUNGEST_REV_HEADER) == 0) { opt_ctx->youngest_rev = SVN_STR_TO_REV(val); } else if (svn_cstring_casecmp(key, SVN_DAV_ALLOW_BULK_UPDATES) == 0) { session->server_allows_bulk = apr_pstrdup(session->pool, val); } else if (svn_cstring_casecmp(key, SVN_DAV_SUPPORTED_POSTS_HEADER) == 0) { /* May contain multiple values, separated by commas. */ int i; apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE, session->pool); for (i = 0; i < vals->nelts; i++) { const char *post_val = APR_ARRAY_IDX(vals, i, const char *); svn_hash_sets(session->supported_posts, post_val, (void *)1); } } else if (svn_cstring_casecmp(key, SVN_DAV_REPOSITORY_MERGEINFO) == 0)