summaryrefslogtreecommitdiff
path: root/subversion/libsvn_ra_serf/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_serf/options.c')
-rw-r--r--subversion/libsvn_ra_serf/options.c611
1 files changed, 332 insertions, 279 deletions
diff --git a/subversion/libsvn_ra_serf/options.c b/subversion/libsvn_ra_serf/options.c
index 8bdc8fd..5389b04 100644
--- a/subversion/libsvn_ra_serf/options.c
+++ b/subversion/libsvn_ra_serf/options.c
@@ -28,10 +28,12 @@
#include <serf.h>
#include "svn_dirent_uri.h"
+#include "svn_hash.h"
#include "svn_pools.h"
#include "svn_ra.h"
#include "svn_dav.h"
#include "svn_xml.h"
+#include "svn_ctype.h"
#include "../libsvn_ra/ra_loader.h"
#include "svn_private_config.h"
@@ -48,167 +50,68 @@
/*
* This enum represents the current state of our XML parsing for an OPTIONS.
*/
-typedef enum options_state_e {
+enum options_state_e {
+ INITIAL = 0,
OPTIONS,
ACTIVITY_COLLECTION,
HREF
-} options_state_e;
-
-typedef struct options_state_list_t {
- /* The current state that we are in now. */
- options_state_e state;
-
- /* The previous state we were in. */
- struct options_state_list_t *prev;
-} options_state_list_t;
+};
-struct svn_ra_serf__options_context_t {
+typedef struct options_context_t {
/* pool to allocate memory from */
apr_pool_t *pool;
- const char *attr_val;
- apr_size_t attr_val_len;
- svn_boolean_t collect_cdata;
-
- /* Current state we're in */
- options_state_list_t *state;
- options_state_list_t *free_state;
-
- /* HTTP Status code */
- int status_code;
-
- /* are we done? */
- svn_boolean_t done;
+ /* Have we extracted options values from the headers already? */
+ svn_boolean_t headers_processed;
svn_ra_serf__session_t *session;
svn_ra_serf__connection_t *conn;
+ svn_ra_serf__handler_t *handler;
- const char *path;
+ svn_ra_serf__response_handler_t inner_handler;
+ void *inner_baton;
const char *activity_collection;
svn_revnum_t youngest_rev;
- serf_response_acceptor_t acceptor;
- serf_response_handler_t handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
+} options_context_t;
-};
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t options_ttable[] = {
+ { INITIAL, D_, "options-response", OPTIONS,
+ FALSE, { NULL }, FALSE },
-static void
-push_state(svn_ra_serf__options_context_t *options_ctx, options_state_e state)
-{
- options_state_list_t *new_state;
+ { OPTIONS, D_, "activity-collection-set", ACTIVITY_COLLECTION,
+ FALSE, { NULL }, FALSE },
- if (!options_ctx->free_state)
- {
- new_state = apr_palloc(options_ctx->pool, sizeof(*options_ctx->state));
- }
- else
- {
- new_state = options_ctx->free_state;
- options_ctx->free_state = options_ctx->free_state->prev;
- }
- new_state->state = state;
-
- /* Add it to the state chain. */
- new_state->prev = options_ctx->state;
- options_ctx->state = new_state;
-}
-
-static void pop_state(svn_ra_serf__options_context_t *options_ctx)
-{
- options_state_list_t *free_state;
- free_state = options_ctx->state;
- /* advance the current state */
- options_ctx->state = options_ctx->state->prev;
- free_state->prev = options_ctx->free_state;
- options_ctx->free_state = free_state;
-}
-
-static svn_error_t *
-start_options(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- svn_ra_serf__dav_props_t name,
- const char **attrs)
-{
- svn_ra_serf__options_context_t *options_ctx = userData;
+ { ACTIVITY_COLLECTION, D_, "href", HREF,
+ TRUE, { NULL }, TRUE },
- if (!options_ctx->state && strcmp(name.name, "options-response") == 0)
- {
- push_state(options_ctx, OPTIONS);
- }
- else if (!options_ctx->state)
- {
- /* Nothing to do. */
- return SVN_NO_ERROR;
- }
- else if (options_ctx->state->state == OPTIONS &&
- strcmp(name.name, "activity-collection-set") == 0)
- {
- push_state(options_ctx, ACTIVITY_COLLECTION);
- }
- else if (options_ctx->state->state == ACTIVITY_COLLECTION &&
- strcmp(name.name, "href") == 0)
- {
- options_ctx->collect_cdata = TRUE;
- push_state(options_ctx, HREF);
- }
+ { 0 }
+};
- return SVN_NO_ERROR;
-}
+/* Conforms to svn_ra_serf__xml_closed_t */
static svn_error_t *
-end_options(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- svn_ra_serf__dav_props_t name)
+options_closed(svn_ra_serf__xml_estate_t *xes,
+ void *baton,
+ int leaving_state,
+ const svn_string_t *cdata,
+ apr_hash_t *attrs,
+ apr_pool_t *scratch_pool)
{
- svn_ra_serf__options_context_t *options_ctx = userData;
- options_state_list_t *cur_state;
-
- if (!options_ctx->state)
- {
- return SVN_NO_ERROR;
- }
+ options_context_t *opt_ctx = baton;
- cur_state = options_ctx->state;
+ SVN_ERR_ASSERT(leaving_state == HREF);
+ SVN_ERR_ASSERT(cdata != NULL);
- if (cur_state->state == OPTIONS &&
- strcmp(name.name, "options-response") == 0)
- {
- pop_state(options_ctx);
- }
- else if (cur_state->state == ACTIVITY_COLLECTION &&
- strcmp(name.name, "activity-collection-set") == 0)
- {
- pop_state(options_ctx);
- }
- else if (cur_state->state == HREF &&
- strcmp(name.name, "href") == 0)
- {
- options_ctx->collect_cdata = FALSE;
- options_ctx->activity_collection =
- svn_urlpath__canonicalize(options_ctx->attr_val, options_ctx->pool);
- pop_state(options_ctx);
- }
+ opt_ctx->activity_collection = svn_urlpath__canonicalize(cdata->data,
+ opt_ctx->pool);
return SVN_NO_ERROR;
}
-static svn_error_t *
-cdata_options(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- const char *data,
- apr_size_t len)
-{
- svn_ra_serf__options_context_t *ctx = userData;
- if (ctx->collect_cdata)
- {
- svn_ra_serf__expand_string(&ctx->attr_val, &ctx->attr_val_len,
- data, len, ctx->pool);
- }
-
- return SVN_NO_ERROR;
-}
static svn_error_t *
create_options_body(serf_bucket_t **body_bkt,
@@ -229,47 +132,17 @@ create_options_body(serf_bucket_t **body_bkt,
return SVN_NO_ERROR;
}
-svn_boolean_t*
-svn_ra_serf__get_options_done_ptr(svn_ra_serf__options_context_t *ctx)
-{
- return &ctx->done;
-}
-
-const char *
-svn_ra_serf__options_get_activity_collection(svn_ra_serf__options_context_t *ctx)
-{
- return ctx->activity_collection;
-}
-
-svn_revnum_t
-svn_ra_serf__options_get_youngest_rev(svn_ra_serf__options_context_t *ctx)
-{
- return ctx->youngest_rev;
-}
-
-/* Context for both options_response_handler() and capabilities callback. */
-struct options_response_ctx_t {
- /* Baton for __handle_xml_parser() */
- svn_ra_serf__xml_parser_t *parser_ctx;
-
- /* Session into which we'll store server capabilities */
- svn_ra_serf__session_t *session;
-
- /* For temporary work only. */
- apr_pool_t *pool;
-};
-
/* We use these static pointers so we can employ pointer comparison
* of our capabilities hash members instead of strcmp()ing all over
* the place.
*/
/* Both server and repository support the capability. */
-static const char *capability_yes = "yes";
+static const char *const capability_yes = "yes";
/* Either server or repository does not support the capability. */
-static const char *capability_no = "no";
+static const char *const capability_no = "no";
/* Server supports the capability, but don't yet know if repository does. */
-static const char *capability_server_yes = "server-yes";
+static const char *const capability_server_yes = "server-yes";
/* This implements serf_bucket_headers_do_callback_fn_t.
@@ -279,7 +152,8 @@ capabilities_headers_iterator_callback(void *baton,
const char *key,
const char *val)
{
- struct options_response_ctx_t *orc = baton;
+ options_context_t *opt_ctx = baton;
+ svn_ra_serf__session_t *session = opt_ctx->session;
if (svn_cstring_casecmp(key, "dav") == 0)
{
@@ -287,7 +161,8 @@ capabilities_headers_iterator_callback(void *baton,
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, orc->pool);
+ apr_array_header_t *vals = svn_cstring_split(val, ",", TRUE,
+ opt_ctx->pool);
/* Right now we only have a few capabilities to detect, so just
seek for them directly. This could be written slightly more
@@ -296,49 +171,86 @@ capabilities_headers_iterator_callback(void *baton,
if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_DEPTH, vals))
{
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
- APR_HASH_KEY_STRING, capability_yes);
+ 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. */
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_server_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))
{
- apr_hash_set(orc->session->capabilities,
- SVN_RA_CAPABILITY_LOG_REVPROPS,
- APR_HASH_KEY_STRING, capability_yes);
+ 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))
{
- apr_hash_set(orc->session->capabilities,
- SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
- APR_HASH_KEY_STRING, capability_yes);
+ 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))
{
- apr_hash_set(orc->session->capabilities,
- SVN_RA_CAPABILITY_PARTIAL_REPLAY,
- APR_HASH_KEY_STRING, capability_yes);
+ 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;
}
}
/* SVN-specific headers -- if present, server supports HTTP protocol v2 */
- else if (strncmp(key, "SVN", 3) == 0)
+ 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)
{
- orc->session->repos_root = orc->session->session_url;
- orc->session->repos_root.path = apr_pstrdup(orc->session->pool, val);
- orc->session->repos_root_str =
+ 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(orc->session->pool,
- &orc->session->repos_root,
- 0),
- orc->session->pool);
+ apr_uri_unparse(session->pool, &session->repos_root, 0),
+ session->pool);
}
else if (svn_cstring_casecmp(key, SVN_DAV_ME_RESOURCE_HEADER) == 0)
{
@@ -347,44 +259,73 @@ capabilities_headers_iterator_callback(void *baton,
if (!(ignore_v2_env_var
&& apr_strnatcasecmp(ignore_v2_env_var, "yes") == 0))
- orc->session->me_resource = apr_pstrdup(orc->session->pool, val);
+ session->me_resource = apr_pstrdup(session->pool, val);
#else
- orc->session->me_resource = apr_pstrdup(orc->session->pool, val);
+ session->me_resource = apr_pstrdup(session->pool, val);
#endif
}
else if (svn_cstring_casecmp(key, SVN_DAV_REV_STUB_HEADER) == 0)
{
- orc->session->rev_stub = apr_pstrdup(orc->session->pool, val);
+ session->rev_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_REV_ROOT_STUB_HEADER) == 0)
{
- orc->session->rev_root_stub = apr_pstrdup(orc->session->pool, val);
+ session->rev_root_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_TXN_STUB_HEADER) == 0)
{
- orc->session->txn_stub = apr_pstrdup(orc->session->pool, val);
+ session->txn_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_TXN_ROOT_STUB_HEADER) == 0)
{
- orc->session->txn_root_stub = apr_pstrdup(orc->session->pool, val);
+ session->txn_root_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_STUB_HEADER) == 0)
{
- orc->session->vtxn_stub = apr_pstrdup(orc->session->pool, val);
+ session->vtxn_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_VTXN_ROOT_STUB_HEADER) == 0)
{
- orc->session->vtxn_root_stub = apr_pstrdup(orc->session->pool, val);
+ session->vtxn_root_stub = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_REPOS_UUID_HEADER) == 0)
{
- orc->session->uuid = apr_pstrdup(orc->session->pool, val);
+ session->uuid = apr_pstrdup(session->pool, val);
}
else if (svn_cstring_casecmp(key, SVN_DAV_YOUNGEST_REV_HEADER) == 0)
{
- struct svn_ra_serf__options_context_t *user_data =
- orc->parser_ctx->user_data;
- user_data->youngest_rev = SVN_STR_TO_REV(val);
+ 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)
+ {
+ if (svn_cstring_casecmp(val, "yes") == 0)
+ {
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
+ capability_yes);
+ }
+ else if (svn_cstring_casecmp(val, "no") == 0)
+ {
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
+ capability_no);
+ }
}
}
@@ -393,7 +334,7 @@ capabilities_headers_iterator_callback(void *baton,
/* A custom serf_response_handler_t which is mostly a wrapper around
- svn_ra_serf__handle_xml_parser -- it just notices OPTIONS response
+ the expat-based response handler -- it just notices OPTIONS response
headers first, before handing off to the xml parser.
Implements svn_ra_serf__response_handler_t */
static svn_error_t *
@@ -402,86 +343,137 @@ options_response_handler(serf_request_t *request,
void *baton,
apr_pool_t *pool)
{
- struct options_response_ctx_t *orc = baton;
- serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
-
- /* Start out assuming all capabilities are unsupported. */
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_DEPTH,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
- APR_HASH_KEY_STRING, capability_no);
- apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
- APR_HASH_KEY_STRING, capability_no);
-
- /* Then see which ones we can discover. */
- serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback, orc);
-
- /* Execute the 'real' response handler to XML-parse the repsonse body. */
- return svn_ra_serf__handle_xml_parser(request, response,
- orc->parser_ctx, pool);
+ options_context_t *opt_ctx = baton;
+
+ if (!opt_ctx->headers_processed)
+ {
+ svn_ra_serf__session_t *session = opt_ctx->session;
+ serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
+
+ /* Start out assuming all capabilities are unsupported. */
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
+ capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_DEPTH,
+ capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
+ NULL);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
+ capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+ capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_INHERITED_PROPS,
+ capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS,
+ capability_no);
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE,
+ capability_no);
+
+ /* Then see which ones we can discover. */
+ serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback,
+ opt_ctx);
+
+ /* Assume mergeinfo capability unsupported, if didn't recieve information
+ about server or repository mergeinfo capability. */
+ if (!svn_hash_gets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO))
+ svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
+ capability_no);
+
+ opt_ctx->headers_processed = TRUE;
+ }
+
+ /* Execute the 'real' response handler to XML-parse the response body. */
+ return opt_ctx->inner_handler(request, response, opt_ctx->inner_baton, pool);
}
-svn_error_t *
-svn_ra_serf__create_options_req(svn_ra_serf__options_context_t **opt_ctx,
- svn_ra_serf__session_t *session,
- svn_ra_serf__connection_t *conn,
- const char *path,
- apr_pool_t *pool)
+static svn_error_t *
+create_options_req(options_context_t **opt_ctx,
+ svn_ra_serf__session_t *session,
+ svn_ra_serf__connection_t *conn,
+ apr_pool_t *pool)
{
- svn_ra_serf__options_context_t *new_ctx;
+ options_context_t *new_ctx;
+ svn_ra_serf__xml_context_t *xmlctx;
svn_ra_serf__handler_t *handler;
- svn_ra_serf__xml_parser_t *parser_ctx;
- struct options_response_ctx_t *options_response_ctx;
new_ctx = apr_pcalloc(pool, sizeof(*new_ctx));
-
new_ctx->pool = pool;
-
- new_ctx->path = path;
- new_ctx->youngest_rev = SVN_INVALID_REVNUM;
-
new_ctx->session = session;
new_ctx->conn = conn;
- handler = apr_pcalloc(pool, sizeof(*handler));
+ new_ctx->youngest_rev = SVN_INVALID_REVNUM;
+
+ xmlctx = svn_ra_serf__xml_context_create(options_ttable,
+ NULL, options_closed, NULL,
+ new_ctx,
+ pool);
+ handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
handler->method = "OPTIONS";
- handler->path = path;
+ handler->path = session->session_url.path;
handler->body_delegate = create_options_body;
handler->body_type = "text/xml";
handler->conn = conn;
handler->session = session;
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
+ new_ctx->handler = handler;
+
+ new_ctx->inner_handler = handler->response_handler;
+ new_ctx->inner_baton = handler->response_baton;
+ handler->response_handler = options_response_handler;
+ handler->response_baton = new_ctx;
+
+ *opt_ctx = new_ctx;
- parser_ctx->pool = pool;
- parser_ctx->user_data = new_ctx;
- parser_ctx->start = start_options;
- parser_ctx->end = end_options;
- parser_ctx->cdata = cdata_options;
- parser_ctx->done = &new_ctx->done;
- parser_ctx->status_code = &new_ctx->status_code;
+ return SVN_NO_ERROR;
+}
- options_response_ctx = apr_pcalloc(pool, sizeof(*options_response_ctx));
- options_response_ctx->parser_ctx = parser_ctx;
- options_response_ctx->session = session;
- options_response_ctx->pool = pool;
- handler->response_handler = options_response_handler;
- handler->response_baton = options_response_ctx;
+svn_error_t *
+svn_ra_serf__v2_get_youngest_revnum(svn_revnum_t *youngest,
+ svn_ra_serf__connection_t *conn,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__session_t *session = conn->session;
+ options_context_t *opt_ctx;
- svn_ra_serf__request_create(handler);
+ SVN_ERR_ASSERT(SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
- new_ctx->parser_ctx = parser_ctx;
+ SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
+ SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
+ SVN_ERR(svn_ra_serf__error_on_status(opt_ctx->handler->sline,
+ opt_ctx->handler->path,
+ opt_ctx->handler->location));
- *opt_ctx = new_ctx;
+ *youngest = opt_ctx->youngest_rev;
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(*youngest));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_ra_serf__v1_get_activity_collection(const char **activity_url,
+ svn_ra_serf__connection_t *conn,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__session_t *session = conn->session;
+ options_context_t *opt_ctx;
+
+ SVN_ERR_ASSERT(!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session));
+
+ SVN_ERR(create_options_req(&opt_ctx, session, conn, scratch_pool));
+ SVN_ERR(svn_ra_serf__context_run_one(opt_ctx->handler, scratch_pool));
+
+ SVN_ERR(svn_ra_serf__error_on_status(opt_ctx->handler->sline,
+ opt_ctx->handler->path,
+ opt_ctx->handler->location));
+
+ *activity_url = apr_pstrdup(result_pool, opt_ctx->activity_collection);
return SVN_NO_ERROR;
+
}
@@ -493,33 +485,100 @@ svn_ra_serf__exchange_capabilities(svn_ra_serf__session_t *serf_sess,
const char **corrected_url,
apr_pool_t *pool)
{
- svn_ra_serf__options_context_t *opt_ctx;
+ options_context_t *opt_ctx;
svn_error_t *err;
/* This routine automatically fills in serf_sess->capabilities */
- SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, serf_sess,
- serf_sess->conns[0],
- serf_sess->session_url.path, pool));
+ SVN_ERR(create_options_req(&opt_ctx, serf_sess, serf_sess->conns[0], pool));
- err = svn_ra_serf__context_run_wait(
- svn_ra_serf__get_options_done_ptr(opt_ctx), serf_sess, pool);
+ err = svn_ra_serf__context_run_one(opt_ctx->handler, pool);
/* If our caller cares about server redirections, and our response
carries such a thing, report as much. We'll disregard ERR --
it's most likely just a complaint about the response body not
successfully parsing as XML or somesuch. */
- if (corrected_url && (opt_ctx->status_code == 301))
+ if (corrected_url && (opt_ctx->handler->sline.code == 301))
{
svn_error_clear(err);
- *corrected_url = opt_ctx->parser_ctx->location;
+ *corrected_url = opt_ctx->handler->location;
return SVN_NO_ERROR;
}
- return svn_error_compose_create(
- svn_ra_serf__error_on_status(opt_ctx->status_code,
- serf_sess->session_url.path,
- opt_ctx->parser_ctx->location),
- err);
+ SVN_ERR(svn_error_compose_create(
+ svn_ra_serf__error_on_status(opt_ctx->handler->sline,
+ serf_sess->session_url.path,
+ opt_ctx->handler->location),
+ err));
+
+ /* Opportunistically cache any reported activity URL. (We don't
+ want to have to ask for this again later, potentially against an
+ unreadable commit anchor URL.) */
+ if (opt_ctx->activity_collection)
+ {
+ serf_sess->activity_collection_url =
+ apr_pstrdup(serf_sess->pool, opt_ctx->activity_collection);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+create_simple_options_body(serf_bucket_t **body_bkt,
+ void *baton,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool)
+{
+ serf_bucket_t *body;
+ serf_bucket_t *s;
+
+ body = serf_bucket_aggregate_create(alloc);
+ svn_ra_serf__add_xml_header_buckets(body, alloc);
+
+ s = SERF_BUCKET_SIMPLE_STRING("<D:options xmlns:D=\"DAV:\" />", alloc);
+ serf_bucket_aggregate_append(body, s);
+
+ *body_bkt = body;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_ra_serf__probe_proxy(svn_ra_serf__session_t *serf_sess,
+ apr_pool_t *scratch_pool)
+{
+ svn_ra_serf__handler_t *handler;
+
+ handler = apr_pcalloc(scratch_pool, sizeof(*handler));
+ handler->handler_pool = scratch_pool;
+ handler->method = "OPTIONS";
+ handler->path = serf_sess->session_url.path;
+ handler->conn = serf_sess->conns[0];
+ handler->session = serf_sess;
+
+ /* We don't care about the response body, so discard it. */
+ handler->response_handler = svn_ra_serf__handle_discard_body;
+
+ /* We need a simple body, in order to send it in chunked format. */
+ handler->body_delegate = create_simple_options_body;
+
+ /* No special headers. */
+
+ SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+ /* Some versions of nginx in reverse proxy mode will return 411. They want
+ a Content-Length header, rather than chunked requests. We can keep other
+ HTTP/1.1 features, but will disable the chunking. */
+ if (handler->sline.code == 411)
+ {
+ serf_sess->using_chunked_requests = FALSE;
+
+ return SVN_NO_ERROR;
+ }
+ SVN_ERR(svn_ra_serf__error_on_status(handler->sline,
+ handler->path,
+ handler->location));
+
+ return SVN_NO_ERROR;
}
@@ -539,21 +598,16 @@ svn_ra_serf__has_capability(svn_ra_session_t *ra_session,
return SVN_NO_ERROR;
}
- cap_result = apr_hash_get(serf_sess->capabilities,
- capability,
- APR_HASH_KEY_STRING);
+ cap_result = svn_hash_gets(serf_sess->capabilities, capability);
/* If any capability is unknown, they're all unknown, so ask. */
if (cap_result == NULL)
SVN_ERR(svn_ra_serf__exchange_capabilities(serf_sess, NULL, pool));
/* Try again, now that we've fetched the capabilities. */
- cap_result = apr_hash_get(serf_sess->capabilities,
- capability, APR_HASH_KEY_STRING);
+ cap_result = svn_hash_gets(serf_sess->capabilities, capability);
- /* Some capabilities depend on the repository as well as the server.
- NOTE: svn_ra_neon__has_capability() has a very similar code block. If
- you change something here, check there as well. */
+ /* Some capabilities depend on the repository as well as the server. */
if (cap_result == capability_server_yes)
{
if (strcmp(capability, SVN_RA_CAPABILITY_MERGEINFO) == 0)
@@ -597,9 +651,8 @@ svn_ra_serf__has_capability(svn_ra_session_t *ra_session,
else
cap_result = capability_yes;
- apr_hash_set(serf_sess->capabilities,
- SVN_RA_CAPABILITY_MERGEINFO, APR_HASH_KEY_STRING,
- cap_result);
+ svn_hash_sets(serf_sess->capabilities,
+ SVN_RA_CAPABILITY_MERGEINFO, cap_result);
}
else
{