1251881Speter/* 2251881Speter * serf.c : entry point for ra_serf 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#define APR_WANT_STRFUNC 27251881Speter#include <apr_want.h> 28251881Speter 29251881Speter#include <apr_uri.h> 30251881Speter#include <serf.h> 31251881Speter 32251881Speter#include "svn_pools.h" 33251881Speter#include "svn_ra.h" 34251881Speter#include "svn_dav.h" 35251881Speter#include "svn_xml.h" 36251881Speter#include "../libsvn_ra/ra_loader.h" 37251881Speter#include "svn_config.h" 38251881Speter#include "svn_delta.h" 39251881Speter#include "svn_dirent_uri.h" 40251881Speter#include "svn_hash.h" 41251881Speter#include "svn_path.h" 42299742Sdim#include "svn_props.h" 43251881Speter#include "svn_time.h" 44251881Speter#include "svn_version.h" 45251881Speter 46251881Speter#include "private/svn_dav_protocol.h" 47251881Speter#include "private/svn_dep_compat.h" 48251881Speter#include "private/svn_fspath.h" 49251881Speter#include "private/svn_subr_private.h" 50251881Speter#include "svn_private_config.h" 51251881Speter 52251881Speter#include "ra_serf.h" 53251881Speter 54251881Speter 55251881Speter/* Implements svn_ra__vtable_t.get_version(). */ 56251881Speterstatic const svn_version_t * 57251881Speterra_serf_version(void) 58251881Speter{ 59251881Speter SVN_VERSION_BODY; 60251881Speter} 61251881Speter 62251881Speter#define RA_SERF_DESCRIPTION \ 63251881Speter N_("Module for accessing a repository via WebDAV protocol using serf.") 64251881Speter 65262253Speter#define RA_SERF_DESCRIPTION_VER \ 66262253Speter N_("Module for accessing a repository via WebDAV protocol using serf.\n" \ 67299742Sdim " - using serf %d.%d.%d (compiled with %d.%d.%d)") 68262253Speter 69251881Speter/* Implements svn_ra__vtable_t.get_description(). */ 70251881Speterstatic const char * 71262253Speterra_serf_get_description(apr_pool_t *pool) 72251881Speter{ 73262253Speter int major, minor, patch; 74262253Speter 75262253Speter serf_lib_version(&major, &minor, &patch); 76299742Sdim return apr_psprintf(pool, _(RA_SERF_DESCRIPTION_VER), 77299742Sdim major, minor, patch, 78299742Sdim SERF_MAJOR_VERSION, 79299742Sdim SERF_MINOR_VERSION, 80299742Sdim SERF_PATCH_VERSION 81299742Sdim ); 82251881Speter} 83251881Speter 84251881Speter/* Implements svn_ra__vtable_t.get_schemes(). */ 85251881Speterstatic const char * const * 86251881Speterra_serf_get_schemes(apr_pool_t *pool) 87251881Speter{ 88251881Speter static const char *serf_ssl[] = { "http", "https", NULL }; 89251881Speter#if 0 90251881Speter /* ### Temporary: to shut up a warning. */ 91251881Speter static const char *serf_no_ssl[] = { "http", NULL }; 92251881Speter#endif 93251881Speter 94251881Speter /* TODO: Runtime detection. */ 95251881Speter return serf_ssl; 96251881Speter} 97251881Speter 98251881Speter/* Load the setting http-auth-types from the global or server specific 99251881Speter section, parse its value and set the types of authentication we should 100251881Speter accept from the server. */ 101251881Speterstatic svn_error_t * 102251881Speterload_http_auth_types(apr_pool_t *pool, svn_config_t *config, 103251881Speter const char *server_group, 104251881Speter int *authn_types) 105251881Speter{ 106251881Speter const char *http_auth_types = NULL; 107251881Speter *authn_types = SERF_AUTHN_NONE; 108251881Speter 109251881Speter svn_config_get(config, &http_auth_types, SVN_CONFIG_SECTION_GLOBAL, 110251881Speter SVN_CONFIG_OPTION_HTTP_AUTH_TYPES, NULL); 111251881Speter 112251881Speter if (server_group) 113251881Speter { 114251881Speter svn_config_get(config, &http_auth_types, server_group, 115251881Speter SVN_CONFIG_OPTION_HTTP_AUTH_TYPES, http_auth_types); 116251881Speter } 117251881Speter 118251881Speter if (http_auth_types) 119251881Speter { 120251881Speter char *token; 121251881Speter char *auth_types_list = apr_palloc(pool, strlen(http_auth_types) + 1); 122251881Speter apr_collapse_spaces(auth_types_list, http_auth_types); 123251881Speter while ((token = svn_cstring_tokenize(";", &auth_types_list)) != NULL) 124251881Speter { 125251881Speter if (svn_cstring_casecmp("basic", token) == 0) 126251881Speter *authn_types |= SERF_AUTHN_BASIC; 127251881Speter else if (svn_cstring_casecmp("digest", token) == 0) 128251881Speter *authn_types |= SERF_AUTHN_DIGEST; 129251881Speter else if (svn_cstring_casecmp("ntlm", token) == 0) 130251881Speter *authn_types |= SERF_AUTHN_NTLM; 131251881Speter else if (svn_cstring_casecmp("negotiate", token) == 0) 132251881Speter *authn_types |= SERF_AUTHN_NEGOTIATE; 133251881Speter else 134251881Speter return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 135251881Speter _("Invalid config: unknown %s " 136251881Speter "'%s'"), 137251881Speter SVN_CONFIG_OPTION_HTTP_AUTH_TYPES, token); 138251881Speter } 139251881Speter } 140251881Speter else 141251881Speter { 142251881Speter /* Nothing specified by the user, so accept all types. */ 143251881Speter *authn_types = SERF_AUTHN_ALL; 144251881Speter } 145251881Speter 146251881Speter return SVN_NO_ERROR; 147251881Speter} 148251881Speter 149251881Speter/* Default HTTP timeout (in seconds); overridden by the 'http-timeout' 150251881Speter runtime configuration variable. */ 151251881Speter#define DEFAULT_HTTP_TIMEOUT 600 152251881Speter 153251881Speterstatic svn_error_t * 154251881Speterload_config(svn_ra_serf__session_t *session, 155251881Speter apr_hash_t *config_hash, 156251881Speter apr_pool_t *pool) 157251881Speter{ 158251881Speter svn_config_t *config, *config_client; 159251881Speter const char *server_group; 160251881Speter const char *proxy_host = NULL; 161251881Speter const char *port_str = NULL; 162251881Speter const char *timeout_str = NULL; 163251881Speter const char *exceptions; 164251881Speter apr_port_t proxy_port; 165253734Speter svn_tristate_t chunked_requests; 166299742Sdim#if SERF_VERSION_AT_LEAST(1, 4, 0) && !defined(SVN_SERF_NO_LOGGING) 167299742Sdim apr_int64_t log_components; 168299742Sdim apr_int64_t log_level; 169299742Sdim#endif 170251881Speter 171251881Speter if (config_hash) 172251881Speter { 173251881Speter config = svn_hash_gets(config_hash, SVN_CONFIG_CATEGORY_SERVERS); 174251881Speter config_client = svn_hash_gets(config_hash, SVN_CONFIG_CATEGORY_CONFIG); 175251881Speter } 176251881Speter else 177251881Speter { 178251881Speter config = NULL; 179251881Speter config_client = NULL; 180251881Speter } 181251881Speter 182251881Speter SVN_ERR(svn_config_get_bool(config, &session->using_compression, 183251881Speter SVN_CONFIG_SECTION_GLOBAL, 184251881Speter SVN_CONFIG_OPTION_HTTP_COMPRESSION, TRUE)); 185251881Speter svn_config_get(config, &timeout_str, SVN_CONFIG_SECTION_GLOBAL, 186251881Speter SVN_CONFIG_OPTION_HTTP_TIMEOUT, NULL); 187251881Speter 188299742Sdim if (session->auth_baton) 189251881Speter { 190251881Speter if (config_client) 191251881Speter { 192299742Sdim svn_auth_set_parameter(session->auth_baton, 193251881Speter SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, 194251881Speter config_client); 195251881Speter } 196251881Speter if (config) 197251881Speter { 198299742Sdim svn_auth_set_parameter(session->auth_baton, 199251881Speter SVN_AUTH_PARAM_CONFIG_CATEGORY_SERVERS, 200251881Speter config); 201251881Speter } 202251881Speter } 203251881Speter 204251881Speter /* Use the default proxy-specific settings if and only if 205251881Speter "http-proxy-exceptions" is not set to exclude this host. */ 206251881Speter svn_config_get(config, &exceptions, SVN_CONFIG_SECTION_GLOBAL, 207251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, ""); 208251881Speter if (! svn_cstring_match_glob_list(session->session_url.hostname, 209251881Speter svn_cstring_split(exceptions, ",", 210251881Speter TRUE, pool))) 211251881Speter { 212251881Speter svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL, 213251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL); 214251881Speter svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL, 215251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL); 216251881Speter svn_config_get(config, &session->proxy_username, 217251881Speter SVN_CONFIG_SECTION_GLOBAL, 218251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL); 219251881Speter svn_config_get(config, &session->proxy_password, 220251881Speter SVN_CONFIG_SECTION_GLOBAL, 221251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL); 222251881Speter } 223251881Speter 224251881Speter /* Load the global ssl settings, if set. */ 225251881Speter SVN_ERR(svn_config_get_bool(config, &session->trust_default_ca, 226251881Speter SVN_CONFIG_SECTION_GLOBAL, 227251881Speter SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA, 228251881Speter TRUE)); 229251881Speter svn_config_get(config, &session->ssl_authorities, SVN_CONFIG_SECTION_GLOBAL, 230251881Speter SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL); 231251881Speter 232251881Speter /* If set, read the flag that tells us to do bulk updates or not. Defaults 233251881Speter to skelta updates. */ 234251881Speter SVN_ERR(svn_config_get_tristate(config, &session->bulk_updates, 235251881Speter SVN_CONFIG_SECTION_GLOBAL, 236251881Speter SVN_CONFIG_OPTION_HTTP_BULK_UPDATES, 237251881Speter "auto", 238251881Speter svn_tristate_unknown)); 239251881Speter 240251881Speter /* Load the maximum number of parallel session connections. */ 241251881Speter SVN_ERR(svn_config_get_int64(config, &session->max_connections, 242251881Speter SVN_CONFIG_SECTION_GLOBAL, 243251881Speter SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS, 244251881Speter SVN_CONFIG_DEFAULT_OPTION_HTTP_MAX_CONNECTIONS)); 245251881Speter 246299742Sdim /* Should we use chunked transfer encoding. */ 247253734Speter SVN_ERR(svn_config_get_tristate(config, &chunked_requests, 248253734Speter SVN_CONFIG_SECTION_GLOBAL, 249299742Sdim SVN_CONFIG_OPTION_HTTP_CHUNKED_REQUESTS, 250253734Speter "auto", svn_tristate_unknown)); 251253734Speter 252299742Sdim#if SERF_VERSION_AT_LEAST(1, 4, 0) && !defined(SVN_SERF_NO_LOGGING) 253299742Sdim SVN_ERR(svn_config_get_int64(config, &log_components, 254299742Sdim SVN_CONFIG_SECTION_GLOBAL, 255299742Sdim SVN_CONFIG_OPTION_SERF_LOG_COMPONENTS, 256299742Sdim SERF_LOGCOMP_NONE)); 257299742Sdim SVN_ERR(svn_config_get_int64(config, &log_level, 258299742Sdim SVN_CONFIG_SECTION_GLOBAL, 259299742Sdim SVN_CONFIG_OPTION_SERF_LOG_LEVEL, 260299742Sdim SERF_LOG_INFO)); 261299742Sdim#endif 262251881Speter 263299742Sdim server_group = svn_auth_get_parameter(session->auth_baton, 264299742Sdim SVN_AUTH_PARAM_SERVER_GROUP); 265299742Sdim 266251881Speter if (server_group) 267251881Speter { 268251881Speter SVN_ERR(svn_config_get_bool(config, &session->using_compression, 269251881Speter server_group, 270251881Speter SVN_CONFIG_OPTION_HTTP_COMPRESSION, 271251881Speter session->using_compression)); 272251881Speter svn_config_get(config, &timeout_str, server_group, 273251881Speter SVN_CONFIG_OPTION_HTTP_TIMEOUT, timeout_str); 274251881Speter 275251881Speter /* Load the group proxy server settings, overriding global 276251881Speter settings. We intentionally ignore 'http-proxy-exceptions' 277251881Speter here because, well, if this site was an exception, why is 278251881Speter there a per-server proxy configuration for it? */ 279251881Speter svn_config_get(config, &proxy_host, server_group, 280251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_HOST, proxy_host); 281251881Speter svn_config_get(config, &port_str, server_group, 282251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_PORT, port_str); 283251881Speter svn_config_get(config, &session->proxy_username, server_group, 284251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, 285251881Speter session->proxy_username); 286251881Speter svn_config_get(config, &session->proxy_password, server_group, 287251881Speter SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, 288251881Speter session->proxy_password); 289251881Speter 290251881Speter /* Load the group ssl settings. */ 291251881Speter SVN_ERR(svn_config_get_bool(config, &session->trust_default_ca, 292251881Speter server_group, 293251881Speter SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA, 294251881Speter session->trust_default_ca)); 295251881Speter svn_config_get(config, &session->ssl_authorities, server_group, 296251881Speter SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, 297251881Speter session->ssl_authorities); 298251881Speter 299251881Speter /* Load the group bulk updates flag. */ 300251881Speter SVN_ERR(svn_config_get_tristate(config, &session->bulk_updates, 301251881Speter server_group, 302251881Speter SVN_CONFIG_OPTION_HTTP_BULK_UPDATES, 303251881Speter "auto", 304251881Speter session->bulk_updates)); 305251881Speter 306251881Speter /* Load the maximum number of parallel session connections, 307251881Speter overriding global values. */ 308251881Speter SVN_ERR(svn_config_get_int64(config, &session->max_connections, 309251881Speter server_group, 310251881Speter SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS, 311251881Speter session->max_connections)); 312253734Speter 313299742Sdim /* Should we use chunked transfer encoding. */ 314253734Speter SVN_ERR(svn_config_get_tristate(config, &chunked_requests, 315253734Speter server_group, 316299742Sdim SVN_CONFIG_OPTION_HTTP_CHUNKED_REQUESTS, 317253734Speter "auto", chunked_requests)); 318299742Sdim 319299742Sdim#if SERF_VERSION_AT_LEAST(1, 4, 0) && !defined(SVN_SERF_NO_LOGGING) 320299742Sdim SVN_ERR(svn_config_get_int64(config, &log_components, 321299742Sdim server_group, 322299742Sdim SVN_CONFIG_OPTION_SERF_LOG_COMPONENTS, 323299742Sdim log_components)); 324299742Sdim SVN_ERR(svn_config_get_int64(config, &log_level, 325299742Sdim server_group, 326299742Sdim SVN_CONFIG_OPTION_SERF_LOG_LEVEL, 327299742Sdim log_level)); 328299742Sdim#endif 329251881Speter } 330251881Speter 331299742Sdim#if SERF_VERSION_AT_LEAST(1, 4, 0) && !defined(SVN_SERF_NO_LOGGING) 332299742Sdim if (log_components != SERF_LOGCOMP_NONE) 333299742Sdim { 334299742Sdim serf_log_output_t *output; 335299742Sdim apr_status_t status; 336299742Sdim 337299742Sdim status = serf_logging_create_stream_output(&output, 338299742Sdim session->context, 339299742Sdim (apr_uint32_t)log_level, 340299742Sdim (apr_uint32_t)log_components, 341299742Sdim SERF_LOG_DEFAULT_LAYOUT, 342299742Sdim stderr, 343299742Sdim pool); 344299742Sdim 345299742Sdim if (!status) 346299742Sdim serf_logging_add_output(session->context, output); 347299742Sdim } 348299742Sdim#endif 349299742Sdim 350251881Speter /* Don't allow the http-max-connections value to be larger than our 351251881Speter compiled-in limit, or to be too small to operate. Broken 352251881Speter functionality and angry administrators are equally undesirable. */ 353251881Speter if (session->max_connections > SVN_RA_SERF__MAX_CONNECTIONS_LIMIT) 354251881Speter session->max_connections = SVN_RA_SERF__MAX_CONNECTIONS_LIMIT; 355251881Speter if (session->max_connections < 2) 356251881Speter session->max_connections = 2; 357251881Speter 358251881Speter /* Parse the connection timeout value, if any. */ 359251881Speter session->timeout = apr_time_from_sec(DEFAULT_HTTP_TIMEOUT); 360251881Speter if (timeout_str) 361251881Speter { 362251881Speter char *endstr; 363251881Speter const long int timeout = strtol(timeout_str, &endstr, 10); 364251881Speter 365251881Speter if (*endstr) 366251881Speter return svn_error_create(SVN_ERR_BAD_CONFIG_VALUE, NULL, 367251881Speter _("Invalid config: illegal character in " 368251881Speter "timeout value")); 369251881Speter if (timeout < 0) 370251881Speter return svn_error_create(SVN_ERR_BAD_CONFIG_VALUE, NULL, 371251881Speter _("Invalid config: negative timeout value")); 372251881Speter session->timeout = apr_time_from_sec(timeout); 373251881Speter } 374251881Speter SVN_ERR_ASSERT(session->timeout >= 0); 375251881Speter 376251881Speter /* Convert the proxy port value, if any. */ 377251881Speter if (port_str) 378251881Speter { 379251881Speter char *endstr; 380251881Speter const long int port = strtol(port_str, &endstr, 10); 381251881Speter 382251881Speter if (*endstr) 383251881Speter return svn_error_create(SVN_ERR_RA_ILLEGAL_URL, NULL, 384251881Speter _("Invalid URL: illegal character in proxy " 385251881Speter "port number")); 386251881Speter if (port < 0) 387251881Speter return svn_error_create(SVN_ERR_RA_ILLEGAL_URL, NULL, 388251881Speter _("Invalid URL: negative proxy port number")); 389251881Speter if (port > 65535) 390251881Speter return svn_error_create(SVN_ERR_RA_ILLEGAL_URL, NULL, 391251881Speter _("Invalid URL: proxy port number greater " 392251881Speter "than maximum TCP port number 65535")); 393251881Speter proxy_port = (apr_port_t) port; 394251881Speter } 395251881Speter else 396251881Speter { 397251881Speter proxy_port = 80; 398251881Speter } 399251881Speter 400251881Speter if (proxy_host) 401251881Speter { 402251881Speter apr_sockaddr_t *proxy_addr; 403251881Speter apr_status_t status; 404251881Speter 405251881Speter status = apr_sockaddr_info_get(&proxy_addr, proxy_host, 406251881Speter APR_UNSPEC, proxy_port, 0, 407251881Speter session->pool); 408251881Speter if (status) 409251881Speter { 410251881Speter return svn_ra_serf__wrap_err( 411251881Speter status, _("Could not resolve proxy server '%s'"), 412251881Speter proxy_host); 413251881Speter } 414251881Speter session->using_proxy = TRUE; 415251881Speter serf_config_proxy(session->context, proxy_addr); 416251881Speter } 417251881Speter else 418251881Speter { 419251881Speter session->using_proxy = FALSE; 420251881Speter } 421251881Speter 422253734Speter /* Setup detect_chunking and using_chunked_requests based on 423253734Speter * the chunked_requests tristate */ 424253734Speter if (chunked_requests == svn_tristate_unknown) 425253734Speter { 426253734Speter session->detect_chunking = TRUE; 427253734Speter session->using_chunked_requests = TRUE; 428253734Speter } 429253734Speter else if (chunked_requests == svn_tristate_true) 430253734Speter { 431253734Speter session->detect_chunking = FALSE; 432253734Speter session->using_chunked_requests = TRUE; 433253734Speter } 434253734Speter else /* chunked_requests == svn_tristate_false */ 435253734Speter { 436253734Speter session->detect_chunking = FALSE; 437253734Speter session->using_chunked_requests = FALSE; 438253734Speter } 439253734Speter 440251881Speter /* Setup authentication. */ 441251881Speter SVN_ERR(load_http_auth_types(pool, config, server_group, 442251881Speter &session->authn_types)); 443251881Speter serf_config_authn_types(session->context, session->authn_types); 444251881Speter serf_config_credentials_callback(session->context, 445251881Speter svn_ra_serf__credentials_callback); 446251881Speter 447251881Speter return SVN_NO_ERROR; 448251881Speter} 449251881Speter#undef DEFAULT_HTTP_TIMEOUT 450251881Speter 451251881Speterstatic void 452251881Spetersvn_ra_serf__progress(void *progress_baton, apr_off_t read, apr_off_t written) 453251881Speter{ 454251881Speter const svn_ra_serf__session_t *serf_sess = progress_baton; 455251881Speter if (serf_sess->progress_func) 456251881Speter { 457251881Speter serf_sess->progress_func(read + written, -1, 458251881Speter serf_sess->progress_baton, 459251881Speter serf_sess->pool); 460251881Speter } 461251881Speter} 462251881Speter 463262253Speter/** Our User-Agent string. */ 464262253Speterstatic const char * 465262253Speterget_user_agent_string(apr_pool_t *pool) 466262253Speter{ 467262253Speter int major, minor, patch; 468262253Speter serf_lib_version(&major, &minor, &patch); 469262253Speter 470262253Speter return apr_psprintf(pool, "SVN/%s (%s) serf/%d.%d.%d", 471262253Speter SVN_VER_NUMBER, SVN_BUILD_TARGET, 472262253Speter major, minor, patch); 473262253Speter} 474262253Speter 475251881Speter/* Implements svn_ra__vtable_t.open_session(). */ 476251881Speterstatic svn_error_t * 477251881Spetersvn_ra_serf__open(svn_ra_session_t *session, 478251881Speter const char **corrected_url, 479251881Speter const char *session_URL, 480251881Speter const svn_ra_callbacks2_t *callbacks, 481251881Speter void *callback_baton, 482299742Sdim svn_auth_baton_t *auth_baton, 483251881Speter apr_hash_t *config, 484299742Sdim apr_pool_t *result_pool, 485299742Sdim apr_pool_t *scratch_pool) 486251881Speter{ 487251881Speter apr_status_t status; 488251881Speter svn_ra_serf__session_t *serf_sess; 489251881Speter apr_uri_t url; 490251881Speter const char *client_string = NULL; 491253734Speter svn_error_t *err; 492251881Speter 493251881Speter if (corrected_url) 494251881Speter *corrected_url = NULL; 495251881Speter 496299742Sdim serf_sess = apr_pcalloc(result_pool, sizeof(*serf_sess)); 497299742Sdim serf_sess->pool = result_pool; 498299742Sdim if (config) 499299742Sdim SVN_ERR(svn_config_copy_config(&serf_sess->config, config, result_pool)); 500299742Sdim else 501299742Sdim serf_sess->config = NULL; 502251881Speter serf_sess->wc_callbacks = callbacks; 503251881Speter serf_sess->wc_callback_baton = callback_baton; 504299742Sdim serf_sess->auth_baton = auth_baton; 505251881Speter serf_sess->progress_func = callbacks->progress_func; 506251881Speter serf_sess->progress_baton = callbacks->progress_baton; 507251881Speter serf_sess->cancel_func = callbacks->cancel_func; 508251881Speter serf_sess->cancel_baton = callback_baton; 509251881Speter 510251881Speter /* todo: reuse serf context across sessions */ 511251881Speter serf_sess->context = serf_context_create(serf_sess->pool); 512251881Speter 513251881Speter SVN_ERR(svn_ra_serf__blncache_create(&serf_sess->blncache, 514251881Speter serf_sess->pool)); 515251881Speter 516251881Speter 517299742Sdim SVN_ERR(svn_ra_serf__uri_parse(&url, session_URL, serf_sess->pool)); 518299742Sdim 519251881Speter if (!url.port) 520251881Speter { 521251881Speter url.port = apr_uri_port_of_scheme(url.scheme); 522251881Speter } 523251881Speter serf_sess->session_url = url; 524251881Speter serf_sess->session_url_str = apr_pstrdup(serf_sess->pool, session_URL); 525251881Speter serf_sess->using_ssl = (svn_cstring_casecmp(url.scheme, "https") == 0); 526251881Speter 527251881Speter serf_sess->supports_deadprop_count = svn_tristate_unknown; 528251881Speter 529251881Speter serf_sess->capabilities = apr_hash_make(serf_sess->pool); 530251881Speter 531251881Speter /* We have to assume that the server only supports HTTP/1.0. Once it's clear 532251881Speter HTTP/1.1 is supported, we can upgrade. */ 533251881Speter serf_sess->http10 = TRUE; 534251881Speter 535253734Speter /* If we switch to HTTP/1.1, then we will use chunked requests. We may disable 536253734Speter this, if we find an intervening proxy does not support chunked requests. */ 537253734Speter serf_sess->using_chunked_requests = TRUE; 538253734Speter 539251881Speter SVN_ERR(load_config(serf_sess, config, serf_sess->pool)); 540251881Speter 541251881Speter serf_sess->conns[0] = apr_pcalloc(serf_sess->pool, 542251881Speter sizeof(*serf_sess->conns[0])); 543251881Speter serf_sess->conns[0]->bkt_alloc = 544251881Speter serf_bucket_allocator_create(serf_sess->pool, NULL, NULL); 545251881Speter serf_sess->conns[0]->session = serf_sess; 546251881Speter serf_sess->conns[0]->last_status_code = -1; 547251881Speter 548251881Speter /* create the user agent string */ 549251881Speter if (callbacks->get_client_string) 550299742Sdim SVN_ERR(callbacks->get_client_string(callback_baton, &client_string, 551299742Sdim scratch_pool)); 552251881Speter 553251881Speter if (client_string) 554299742Sdim serf_sess->useragent = apr_pstrcat(result_pool, 555299742Sdim get_user_agent_string(scratch_pool), 556299742Sdim " ", 557299742Sdim client_string, SVN_VA_NULL); 558251881Speter else 559299742Sdim serf_sess->useragent = get_user_agent_string(result_pool); 560251881Speter 561251881Speter /* go ahead and tell serf about the connection. */ 562251881Speter status = 563251881Speter serf_connection_create2(&serf_sess->conns[0]->conn, 564251881Speter serf_sess->context, 565251881Speter url, 566251881Speter svn_ra_serf__conn_setup, serf_sess->conns[0], 567251881Speter svn_ra_serf__conn_closed, serf_sess->conns[0], 568251881Speter serf_sess->pool); 569251881Speter if (status) 570251881Speter return svn_ra_serf__wrap_err(status, NULL); 571251881Speter 572251881Speter /* Set the progress callback. */ 573251881Speter serf_context_set_progress_cb(serf_sess->context, svn_ra_serf__progress, 574251881Speter serf_sess); 575251881Speter 576251881Speter serf_sess->num_conns = 1; 577251881Speter 578251881Speter session->priv = serf_sess; 579251881Speter 580299742Sdim /* The following code explicitly works around a bug in serf <= r2319 / 1.3.8 581299742Sdim where serf doesn't report the request as failed/cancelled when the 582299742Sdim authorization request handler fails to handle the request. 583253734Speter 584299742Sdim As long as we allocate the request in a subpool of the serf connection 585299742Sdim pool, we know that the handler is always cleaned before the connection. 586299742Sdim 587299742Sdim Luckily our caller now passes us two pools which handle this case. 588299742Sdim */ 589299742Sdim#if defined(SVN_DEBUG) && !SERF_VERSION_AT_LEAST(1,4,0) 590299742Sdim /* Currently ensured by svn_ra_open4(). 591299742Sdim If failing causes segfault in basic_tests.py 48, "basic auth test" */ 592299742Sdim SVN_ERR_ASSERT((serf_sess->pool != scratch_pool) 593299742Sdim && apr_pool_is_ancestor(serf_sess->pool, scratch_pool)); 594299742Sdim#endif 595299742Sdim 596299742Sdim err = svn_ra_serf__exchange_capabilities(serf_sess, corrected_url, 597299742Sdim result_pool, scratch_pool); 598299742Sdim 599253734Speter /* serf should produce a usable error code instead of APR_EGENERAL */ 600253734Speter if (err && err->apr_err == APR_EGENERAL) 601253734Speter err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, err, 602253734Speter _("Connection to '%s' failed"), session_URL); 603253734Speter SVN_ERR(err); 604253734Speter 605253734Speter /* We have set up a useful connection (that doesn't indication a redirect). 606253734Speter If we've been told there is possibly a worrisome proxy in our path to the 607253734Speter server AND we switched to HTTP/1.1 (chunked requests), then probe for 608253734Speter problems in any proxy. */ 609253734Speter if ((corrected_url == NULL || *corrected_url == NULL) 610253734Speter && serf_sess->detect_chunking && !serf_sess->http10) 611299742Sdim SVN_ERR(svn_ra_serf__probe_proxy(serf_sess, scratch_pool)); 612253734Speter 613253734Speter return SVN_NO_ERROR; 614251881Speter} 615251881Speter 616299742Sdim/* Implements svn_ra__vtable_t.dup_session */ 617299742Sdimstatic svn_error_t * 618299742Sdimra_serf_dup_session(svn_ra_session_t *new_session, 619299742Sdim svn_ra_session_t *old_session, 620299742Sdim const char *new_session_url, 621299742Sdim apr_pool_t *result_pool, 622299742Sdim apr_pool_t *scratch_pool) 623299742Sdim{ 624299742Sdim svn_ra_serf__session_t *old_sess = old_session->priv; 625299742Sdim svn_ra_serf__session_t *new_sess; 626299742Sdim apr_status_t status; 627299742Sdim 628299742Sdim new_sess = apr_pmemdup(result_pool, old_sess, sizeof(*new_sess)); 629299742Sdim 630299742Sdim new_sess->pool = result_pool; 631299742Sdim 632299742Sdim if (new_sess->config) 633299742Sdim SVN_ERR(svn_config_copy_config(&new_sess->config, new_sess->config, 634299742Sdim result_pool)); 635299742Sdim 636299742Sdim /* max_connections */ 637299742Sdim /* using_ssl */ 638299742Sdim /* using_compression */ 639299742Sdim /* http10 */ 640299742Sdim /* using_chunked_requests */ 641299742Sdim /* detect_chunking */ 642299742Sdim 643299742Sdim if (new_sess->useragent) 644299742Sdim new_sess->useragent = apr_pstrdup(result_pool, new_sess->useragent); 645299742Sdim 646299742Sdim if (new_sess->vcc_url) 647299742Sdim new_sess->vcc_url = apr_pstrdup(result_pool, new_sess->vcc_url); 648299742Sdim 649299742Sdim new_sess->auth_state = NULL; 650299742Sdim new_sess->auth_attempts = 0; 651299742Sdim 652299742Sdim /* Callback functions to get info from WC */ 653299742Sdim /* wc_callbacks */ 654299742Sdim /* wc_callback_baton */ 655299742Sdim 656299742Sdim /* progress_func */ 657299742Sdim /* progress_baton */ 658299742Sdim 659299742Sdim /* cancel_func */ 660299742Sdim /* cancel_baton */ 661299742Sdim 662299742Sdim /* shim_callbacks */ 663299742Sdim 664299742Sdim new_sess->pending_error = NULL; 665299742Sdim 666299742Sdim /* authn_types */ 667299742Sdim 668299742Sdim /* Keys and values are static */ 669299742Sdim if (new_sess->capabilities) 670299742Sdim new_sess->capabilities = apr_hash_copy(result_pool, new_sess->capabilities); 671299742Sdim 672299742Sdim if (new_sess->activity_collection_url) 673299742Sdim { 674299742Sdim new_sess->activity_collection_url 675299742Sdim = apr_pstrdup(result_pool, new_sess->activity_collection_url); 676299742Sdim } 677299742Sdim 678299742Sdim /* using_proxy */ 679299742Sdim 680299742Sdim if (new_sess->proxy_username) 681299742Sdim { 682299742Sdim new_sess->proxy_username 683299742Sdim = apr_pstrdup(result_pool, new_sess->proxy_username); 684299742Sdim } 685299742Sdim 686299742Sdim if (new_sess->proxy_password) 687299742Sdim { 688299742Sdim new_sess->proxy_username 689299742Sdim = apr_pstrdup(result_pool, new_sess->proxy_password); 690299742Sdim } 691299742Sdim 692299742Sdim new_sess->proxy_auth_attempts = 0; 693299742Sdim 694299742Sdim /* trust_default_ca */ 695299742Sdim 696299742Sdim if (new_sess->ssl_authorities) 697299742Sdim { 698299742Sdim new_sess->ssl_authorities = apr_pstrdup(result_pool, 699299742Sdim new_sess->ssl_authorities); 700299742Sdim } 701299742Sdim 702299742Sdim if (new_sess->uuid) 703299742Sdim new_sess->uuid = apr_pstrdup(result_pool, new_sess->uuid); 704299742Sdim 705299742Sdim /* timeout */ 706299742Sdim /* supports_deadprop_count */ 707299742Sdim 708299742Sdim if (new_sess->me_resource) 709299742Sdim new_sess->me_resource = apr_pstrdup(result_pool, new_sess->me_resource); 710299742Sdim if (new_sess->rev_stub) 711299742Sdim new_sess->rev_stub = apr_pstrdup(result_pool, new_sess->rev_stub); 712299742Sdim if (new_sess->txn_stub) 713299742Sdim new_sess->txn_stub = apr_pstrdup(result_pool, new_sess->txn_stub); 714299742Sdim if (new_sess->txn_root_stub) 715299742Sdim new_sess->txn_root_stub = apr_pstrdup(result_pool, 716299742Sdim new_sess->txn_root_stub); 717299742Sdim if (new_sess->vtxn_stub) 718299742Sdim new_sess->vtxn_stub = apr_pstrdup(result_pool, new_sess->vtxn_stub); 719299742Sdim if (new_sess->vtxn_root_stub) 720299742Sdim new_sess->vtxn_root_stub = apr_pstrdup(result_pool, 721299742Sdim new_sess->vtxn_root_stub); 722299742Sdim 723299742Sdim /* Keys and values are static */ 724299742Sdim if (new_sess->supported_posts) 725299742Sdim new_sess->supported_posts = apr_hash_copy(result_pool, 726299742Sdim new_sess->supported_posts); 727299742Sdim 728299742Sdim /* ### Can we copy this? */ 729299742Sdim SVN_ERR(svn_ra_serf__blncache_create(&new_sess->blncache, 730299742Sdim new_sess->pool)); 731299742Sdim 732299742Sdim if (new_sess->server_allows_bulk) 733299742Sdim new_sess->server_allows_bulk = apr_pstrdup(result_pool, 734299742Sdim new_sess->server_allows_bulk); 735299742Sdim 736299742Sdim new_sess->repos_root_str = apr_pstrdup(result_pool, 737299742Sdim new_sess->repos_root_str); 738299742Sdim SVN_ERR(svn_ra_serf__uri_parse(&new_sess->repos_root, 739299742Sdim new_sess->repos_root_str, 740299742Sdim result_pool)); 741299742Sdim 742299742Sdim new_sess->session_url_str = apr_pstrdup(result_pool, new_session_url); 743299742Sdim 744299742Sdim SVN_ERR(svn_ra_serf__uri_parse(&new_sess->session_url, 745299742Sdim new_sess->session_url_str, 746299742Sdim result_pool)); 747299742Sdim 748299742Sdim /* svn_boolean_t supports_inline_props */ 749299742Sdim /* supports_rev_rsrc_replay */ 750299742Sdim 751299742Sdim new_sess->context = serf_context_create(result_pool); 752299742Sdim 753299742Sdim SVN_ERR(load_config(new_sess, old_sess->config, result_pool)); 754299742Sdim 755299742Sdim new_sess->conns[0] = apr_pcalloc(result_pool, 756299742Sdim sizeof(*new_sess->conns[0])); 757299742Sdim new_sess->conns[0]->bkt_alloc = 758299742Sdim serf_bucket_allocator_create(result_pool, NULL, NULL); 759299742Sdim new_sess->conns[0]->session = new_sess; 760299742Sdim new_sess->conns[0]->last_status_code = -1; 761299742Sdim 762299742Sdim /* go ahead and tell serf about the connection. */ 763299742Sdim status = 764299742Sdim serf_connection_create2(&new_sess->conns[0]->conn, 765299742Sdim new_sess->context, 766299742Sdim new_sess->session_url, 767299742Sdim svn_ra_serf__conn_setup, new_sess->conns[0], 768299742Sdim svn_ra_serf__conn_closed, new_sess->conns[0], 769299742Sdim result_pool); 770299742Sdim if (status) 771299742Sdim return svn_ra_serf__wrap_err(status, NULL); 772299742Sdim 773299742Sdim /* Set the progress callback. */ 774299742Sdim serf_context_set_progress_cb(new_sess->context, svn_ra_serf__progress, 775299742Sdim new_sess); 776299742Sdim 777299742Sdim new_sess->num_conns = 1; 778299742Sdim new_sess->cur_conn = 0; 779299742Sdim 780299742Sdim new_session->priv = new_sess; 781299742Sdim 782299742Sdim return SVN_NO_ERROR; 783299742Sdim} 784299742Sdim 785251881Speter/* Implements svn_ra__vtable_t.reparent(). */ 786299742Sdimsvn_error_t * 787251881Spetersvn_ra_serf__reparent(svn_ra_session_t *ra_session, 788251881Speter const char *url, 789251881Speter apr_pool_t *pool) 790251881Speter{ 791251881Speter svn_ra_serf__session_t *session = ra_session->priv; 792251881Speter apr_uri_t new_url; 793251881Speter 794251881Speter /* If it's the URL we already have, wave our hands and do nothing. */ 795251881Speter if (strcmp(session->session_url_str, url) == 0) 796251881Speter { 797251881Speter return SVN_NO_ERROR; 798251881Speter } 799251881Speter 800251881Speter if (!session->repos_root_str) 801251881Speter { 802251881Speter const char *vcc_url; 803299742Sdim SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool)); 804251881Speter } 805251881Speter 806251881Speter if (!svn_uri__is_ancestor(session->repos_root_str, url)) 807251881Speter { 808251881Speter return svn_error_createf( 809251881Speter SVN_ERR_RA_ILLEGAL_URL, NULL, 810251881Speter _("URL '%s' is not a child of the session's repository root " 811251881Speter "URL '%s'"), url, session->repos_root_str); 812251881Speter } 813251881Speter 814299742Sdim SVN_ERR(svn_ra_serf__uri_parse(&new_url, url, pool)); 815251881Speter 816251881Speter /* ### Maybe we should use a string buffer for these strings so we 817251881Speter ### don't allocate memory in the session on every reparent? */ 818299742Sdim session->session_url.path = apr_pstrdup(session->pool, new_url.path); 819251881Speter session->session_url_str = apr_pstrdup(session->pool, url); 820251881Speter 821251881Speter return SVN_NO_ERROR; 822251881Speter} 823251881Speter 824251881Speter/* Implements svn_ra__vtable_t.get_session_url(). */ 825251881Speterstatic svn_error_t * 826251881Spetersvn_ra_serf__get_session_url(svn_ra_session_t *ra_session, 827251881Speter const char **url, 828251881Speter apr_pool_t *pool) 829251881Speter{ 830251881Speter svn_ra_serf__session_t *session = ra_session->priv; 831251881Speter *url = apr_pstrdup(pool, session->session_url_str); 832251881Speter return SVN_NO_ERROR; 833251881Speter} 834251881Speter 835251881Speter/* Implements svn_ra__vtable_t.get_latest_revnum(). */ 836251881Speterstatic svn_error_t * 837251881Spetersvn_ra_serf__get_latest_revnum(svn_ra_session_t *ra_session, 838251881Speter svn_revnum_t *latest_revnum, 839251881Speter apr_pool_t *pool) 840251881Speter{ 841251881Speter svn_ra_serf__session_t *session = ra_session->priv; 842251881Speter 843251881Speter return svn_error_trace(svn_ra_serf__get_youngest_revnum( 844251881Speter latest_revnum, session, pool)); 845251881Speter} 846251881Speter 847299742Sdim/* Implementation of svn_ra_serf__rev_proplist(). */ 848251881Speterstatic svn_error_t * 849299742Sdimserf__rev_proplist(svn_ra_session_t *ra_session, 850299742Sdim svn_revnum_t rev, 851299742Sdim const svn_ra_serf__dav_props_t *fetch_props, 852299742Sdim apr_hash_t **ret_props, 853299742Sdim apr_pool_t *result_pool, 854299742Sdim apr_pool_t *scratch_pool) 855251881Speter{ 856251881Speter svn_ra_serf__session_t *session = ra_session->priv; 857251881Speter apr_hash_t *props; 858251881Speter const char *propfind_path; 859299742Sdim svn_ra_serf__handler_t *handler; 860251881Speter 861251881Speter if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session)) 862251881Speter { 863299742Sdim propfind_path = apr_psprintf(scratch_pool, "%s/%ld", session->rev_stub, 864299742Sdim rev); 865251881Speter 866251881Speter /* svn_ra_serf__retrieve_props() wants to added the revision as 867251881Speter a Label to the PROPFIND, which isn't really necessary when 868251881Speter querying a rev-stub URI. *Shrug* Probably okay to leave the 869251881Speter Label, but whatever. */ 870251881Speter rev = SVN_INVALID_REVNUM; 871251881Speter } 872251881Speter else 873251881Speter { 874251881Speter /* Use the VCC as the propfind target path. */ 875299742Sdim SVN_ERR(svn_ra_serf__discover_vcc(&propfind_path, session, 876299742Sdim scratch_pool)); 877251881Speter } 878251881Speter 879299742Sdim props = apr_hash_make(result_pool); 880299742Sdim SVN_ERR(svn_ra_serf__create_propfind_handler(&handler, session, 881299742Sdim propfind_path, rev, "0", 882299742Sdim fetch_props, 883299742Sdim svn_ra_serf__deliver_svn_props, 884299742Sdim props, 885299742Sdim scratch_pool)); 886251881Speter 887299742Sdim SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool)); 888251881Speter 889299742Sdim svn_ra_serf__keep_only_regular_props(props, scratch_pool); 890251881Speter 891299742Sdim *ret_props = props; 892251881Speter 893251881Speter return SVN_NO_ERROR; 894251881Speter} 895251881Speter 896299742Sdim/* Implements svn_ra__vtable_t.rev_proplist(). */ 897251881Speterstatic svn_error_t * 898299742Sdimsvn_ra_serf__rev_proplist(svn_ra_session_t *ra_session, 899299742Sdim svn_revnum_t rev, 900299742Sdim apr_hash_t **ret_props, 901299742Sdim apr_pool_t *result_pool) 902251881Speter{ 903299742Sdim apr_pool_t *scratch_pool = svn_pool_create(result_pool); 904299742Sdim svn_error_t *err; 905251881Speter 906299742Sdim err = serf__rev_proplist(ra_session, rev, all_props, ret_props, 907299742Sdim result_pool, scratch_pool); 908251881Speter 909299742Sdim svn_pool_destroy(scratch_pool); 910299742Sdim return svn_error_trace(err); 911251881Speter} 912251881Speter 913251881Speter 914299742Sdim/* Implements svn_ra__vtable_t.rev_prop(). */ 915299742Sdimsvn_error_t * 916299742Sdimsvn_ra_serf__rev_prop(svn_ra_session_t *session, 917299742Sdim svn_revnum_t rev, 918299742Sdim const char *name, 919299742Sdim svn_string_t **value, 920299742Sdim apr_pool_t *result_pool) 921251881Speter{ 922299742Sdim apr_pool_t *scratch_pool = svn_pool_create(result_pool); 923251881Speter apr_hash_t *props; 924299742Sdim svn_ra_serf__dav_props_t specific_props[2]; 925299742Sdim const svn_ra_serf__dav_props_t *fetch_props = all_props; 926251881Speter 927299742Sdim /* The DAV propfind doesn't allow property fetches for any property name 928299742Sdim as there is no defined way to quote values. If we are just fetching a 929299742Sdim "svn:property" we can safely do this. In other cases we just fetch all 930299742Sdim revision properties and filter the right one out */ 931299742Sdim if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX)-1) == 0 932299742Sdim && !strchr(name + sizeof(SVN_PROP_PREFIX)-1, ':')) 933251881Speter { 934299742Sdim specific_props[0].xmlns = SVN_DAV_PROP_NS_SVN; 935299742Sdim specific_props[0].name = name + sizeof(SVN_PROP_PREFIX)-1; 936299742Sdim specific_props[1].xmlns = NULL; 937299742Sdim specific_props[1].name = NULL; 938251881Speter 939299742Sdim fetch_props = specific_props; 940251881Speter } 941251881Speter 942299742Sdim SVN_ERR(serf__rev_proplist(session, rev, fetch_props, &props, 943299742Sdim result_pool, scratch_pool)); 944251881Speter 945299742Sdim *value = svn_hash_gets(props, name); 946251881Speter 947299742Sdim svn_pool_destroy(scratch_pool); 948251881Speter 949251881Speter return SVN_NO_ERROR; 950251881Speter} 951251881Speter 952251881Spetersvn_error_t * 953251881Spetersvn_ra_serf__get_repos_root(svn_ra_session_t *ra_session, 954251881Speter const char **url, 955251881Speter apr_pool_t *pool) 956251881Speter{ 957251881Speter svn_ra_serf__session_t *session = ra_session->priv; 958251881Speter 959251881Speter if (!session->repos_root_str) 960251881Speter { 961251881Speter const char *vcc_url; 962299742Sdim SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool)); 963251881Speter } 964251881Speter 965251881Speter *url = session->repos_root_str; 966251881Speter return SVN_NO_ERROR; 967251881Speter} 968251881Speter 969251881Speter/* TODO: to fetch the uuid from the repository, we need: 970251881Speter 1. a path that exists in HEAD 971251881Speter 2. a path that's readable 972251881Speter 973251881Speter get_uuid handles the case where a path doesn't exist in HEAD and also the 974251881Speter case where the root of the repository is not readable. 975251881Speter However, it does not handle the case where we're fetching path not existing 976251881Speter in HEAD of a repository with unreadable root directory. 977251881Speter 978251881Speter Implements svn_ra__vtable_t.get_uuid(). 979251881Speter */ 980251881Speterstatic svn_error_t * 981251881Spetersvn_ra_serf__get_uuid(svn_ra_session_t *ra_session, 982251881Speter const char **uuid, 983251881Speter apr_pool_t *pool) 984251881Speter{ 985251881Speter svn_ra_serf__session_t *session = ra_session->priv; 986251881Speter 987251881Speter if (!session->uuid) 988251881Speter { 989251881Speter const char *vcc_url; 990251881Speter 991251881Speter /* We should never get here if we have HTTP v2 support, because 992251881Speter any server with that support should be transmitting the 993251881Speter UUID in the initial OPTIONS response. */ 994251881Speter SVN_ERR_ASSERT(! SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session)); 995251881Speter 996251881Speter /* We're not interested in vcc_url and relative_url, but this call also 997251881Speter stores the repository's uuid in the session. */ 998299742Sdim SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool)); 999251881Speter if (!session->uuid) 1000251881Speter { 1001251881Speter return svn_error_create(SVN_ERR_RA_DAV_RESPONSE_HEADER_BADNESS, NULL, 1002251881Speter _("The UUID property was not found on the " 1003251881Speter "resource or any of its parents")); 1004251881Speter } 1005251881Speter } 1006251881Speter 1007251881Speter *uuid = session->uuid; 1008251881Speter 1009251881Speter return SVN_NO_ERROR; 1010251881Speter} 1011251881Speter 1012251881Speter 1013251881Speterstatic const svn_ra__vtable_t serf_vtable = { 1014251881Speter ra_serf_version, 1015251881Speter ra_serf_get_description, 1016251881Speter ra_serf_get_schemes, 1017251881Speter svn_ra_serf__open, 1018299742Sdim ra_serf_dup_session, 1019251881Speter svn_ra_serf__reparent, 1020251881Speter svn_ra_serf__get_session_url, 1021251881Speter svn_ra_serf__get_latest_revnum, 1022251881Speter svn_ra_serf__get_dated_revision, 1023251881Speter svn_ra_serf__change_rev_prop, 1024251881Speter svn_ra_serf__rev_proplist, 1025251881Speter svn_ra_serf__rev_prop, 1026251881Speter svn_ra_serf__get_commit_editor, 1027251881Speter svn_ra_serf__get_file, 1028251881Speter svn_ra_serf__get_dir, 1029251881Speter svn_ra_serf__get_mergeinfo, 1030251881Speter svn_ra_serf__do_update, 1031251881Speter svn_ra_serf__do_switch, 1032251881Speter svn_ra_serf__do_status, 1033251881Speter svn_ra_serf__do_diff, 1034251881Speter svn_ra_serf__get_log, 1035251881Speter svn_ra_serf__check_path, 1036251881Speter svn_ra_serf__stat, 1037251881Speter svn_ra_serf__get_uuid, 1038251881Speter svn_ra_serf__get_repos_root, 1039251881Speter svn_ra_serf__get_locations, 1040251881Speter svn_ra_serf__get_location_segments, 1041251881Speter svn_ra_serf__get_file_revs, 1042251881Speter svn_ra_serf__lock, 1043251881Speter svn_ra_serf__unlock, 1044251881Speter svn_ra_serf__get_lock, 1045251881Speter svn_ra_serf__get_locks, 1046251881Speter svn_ra_serf__replay, 1047251881Speter svn_ra_serf__has_capability, 1048251881Speter svn_ra_serf__replay_range, 1049251881Speter svn_ra_serf__get_deleted_rev, 1050251881Speter svn_ra_serf__register_editor_shim_callbacks, 1051251881Speter svn_ra_serf__get_inherited_props 1052251881Speter}; 1053251881Speter 1054251881Spetersvn_error_t * 1055251881Spetersvn_ra_serf__init(const svn_version_t *loader_version, 1056251881Speter const svn_ra__vtable_t **vtable, 1057251881Speter apr_pool_t *pool) 1058251881Speter{ 1059251881Speter static const svn_version_checklist_t checklist[] = 1060251881Speter { 1061251881Speter { "svn_subr", svn_subr_version }, 1062251881Speter { "svn_delta", svn_delta_version }, 1063251881Speter { NULL, NULL } 1064251881Speter }; 1065251881Speter int serf_major; 1066251881Speter int serf_minor; 1067251881Speter int serf_patch; 1068251881Speter 1069262253Speter SVN_ERR(svn_ver_check_list2(ra_serf_version(), checklist, svn_ver_equal)); 1070251881Speter 1071251881Speter /* Simplified version check to make sure we can safely use the 1072251881Speter VTABLE parameter. The RA loader does a more exhaustive check. */ 1073251881Speter if (loader_version->major != SVN_VER_MAJOR) 1074251881Speter { 1075251881Speter return svn_error_createf( 1076251881Speter SVN_ERR_VERSION_MISMATCH, NULL, 1077251881Speter _("Unsupported RA loader version (%d) for ra_serf"), 1078251881Speter loader_version->major); 1079251881Speter } 1080251881Speter 1081251881Speter /* Make sure that we have loaded a compatible library: the MAJOR must 1082251881Speter match, and the minor must be at *least* what we compiled against. 1083251881Speter The patch level is simply ignored. */ 1084251881Speter serf_lib_version(&serf_major, &serf_minor, &serf_patch); 1085251881Speter if (serf_major != SERF_MAJOR_VERSION 1086251881Speter || serf_minor < SERF_MINOR_VERSION) 1087251881Speter { 1088251881Speter return svn_error_createf( 1089251881Speter /* ### should return a unique error */ 1090251881Speter SVN_ERR_VERSION_MISMATCH, NULL, 1091251881Speter _("ra_serf was compiled for serf %d.%d.%d but loaded " 1092251881Speter "an incompatible %d.%d.%d library"), 1093251881Speter SERF_MAJOR_VERSION, SERF_MINOR_VERSION, SERF_PATCH_VERSION, 1094251881Speter serf_major, serf_minor, serf_patch); 1095251881Speter } 1096251881Speter 1097251881Speter *vtable = &serf_vtable; 1098251881Speter 1099251881Speter return SVN_NO_ERROR; 1100251881Speter} 1101251881Speter 1102251881Speter/* Compatibility wrapper for pre-1.2 subversions. Needed? */ 1103251881Speter#define NAME "ra_serf" 1104251881Speter#define DESCRIPTION RA_SERF_DESCRIPTION 1105251881Speter#define VTBL serf_vtable 1106251881Speter#define INITFUNC svn_ra_serf__init 1107251881Speter#define COMPAT_INITFUNC svn_ra_serf_init 1108251881Speter#include "../libsvn_ra/wrapper_template.h" 1109