📄 property.c
字号:
/* * property.c : property routines for ra_serf * * ==================================================================== * Copyright (c) 2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <serf.h>#include "svn_path.h"#include "svn_base64.h"#include "ra_serf.h"/* Our current parsing state we're in for the PROPFIND response. */typedef enum { NONE = 0, RESPONSE, PROP, PROPVAL,} prop_state_e;typedef struct { apr_pool_t *pool; /* Current ns, attribute name, and value of the property we're parsing */ const char *ns; const char *name; const char *val; apr_size_t val_len; const char *encoding;} prop_info_t;/* * This structure represents a pending PROPFIND response. */struct svn_ra_serf__propfind_context_t { /* pool to issue allocations from */ apr_pool_t *pool; svn_ra_serf__handler_t *handler; /* associated serf session */ svn_ra_serf__session_t *sess; svn_ra_serf__connection_t *conn; /* the requested path */ const char *path; /* the requested version (number and string form) */ svn_revnum_t rev; const char *label; /* the request depth */ const char *depth; /* the list of requested properties */ const svn_ra_serf__dav_props_t *find_props; /* should we cache the values of this propfind in our session? */ svn_boolean_t cache_props; /* hash table that will be updated with the properties * * This can be shared between multiple svn_ra_serf__propfind_context_t * structures */ apr_hash_t *ret_props; /* If we're dealing with a Depth: 1 response, * we may be dealing with multiple paths. */ const char *current_path; /* Returned status code. */ int status_code; /* Are we done issuing the PROPFIND? */ svn_boolean_t done; /* Context from XML stream */ svn_ra_serf__xml_parser_t *parser_ctx; /* If not-NULL, add us to this list when we're done. */ svn_ra_serf__list_t **done_list; svn_ra_serf__list_t done_item;};const svn_string_t *svn_ra_serf__get_ver_prop_string(apr_hash_t *props, const char *path, svn_revnum_t rev, const char *ns, const char *name){ apr_hash_t *ver_props, *path_props, *ns_props; void *val = NULL; ver_props = apr_hash_get(props, &rev, sizeof(rev)); if (ver_props) { path_props = apr_hash_get(ver_props, path, APR_HASH_KEY_STRING); if (path_props) { ns_props = apr_hash_get(path_props, ns, APR_HASH_KEY_STRING); if (ns_props) { val = apr_hash_get(ns_props, name, APR_HASH_KEY_STRING); } } } return val;}const char *svn_ra_serf__get_ver_prop(apr_hash_t *props, const char *path, svn_revnum_t rev, const char *ns, const char *name){ const svn_string_t *val; val = svn_ra_serf__get_ver_prop_string(props, path, rev, ns, name); if (val) { return val->data; } return NULL;}const char *svn_ra_serf__get_prop(apr_hash_t *props, const char *path, const char *ns, const char *name){ return svn_ra_serf__get_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name);}voidsvn_ra_serf__set_ver_prop(apr_hash_t *props, const char *path, svn_revnum_t rev, const char *ns, const char *name, const svn_string_t *val, apr_pool_t *pool){ apr_hash_t *ver_props, *path_props, *ns_props; ver_props = apr_hash_get(props, &rev, sizeof(rev)); if (!ver_props) { ver_props = apr_hash_make(pool); apr_hash_set(props, apr_pmemdup(pool, &rev, sizeof(rev)), sizeof(rev), ver_props); } path_props = apr_hash_get(ver_props, path, APR_HASH_KEY_STRING); if (!path_props) { path_props = apr_hash_make(pool); path = apr_pstrdup(pool, path); apr_hash_set(ver_props, path, APR_HASH_KEY_STRING, path_props); /* todo: we know that we'll fail the next check, but fall through * for now for simplicity's sake. */ } ns_props = apr_hash_get(path_props, ns, APR_HASH_KEY_STRING); if (!ns_props) { ns_props = apr_hash_make(pool); ns = apr_pstrdup(pool, ns); apr_hash_set(path_props, ns, APR_HASH_KEY_STRING, ns_props); } apr_hash_set(ns_props, name, APR_HASH_KEY_STRING, val);}voidsvn_ra_serf__set_prop(apr_hash_t *props, const char *path, const char *ns, const char *name, const svn_string_t *val, apr_pool_t *pool){ svn_ra_serf__set_ver_prop(props, path, SVN_INVALID_REVNUM, ns, name, val, pool);}static prop_info_t *push_state(svn_ra_serf__xml_parser_t *parser, svn_ra_serf__propfind_context_t *propfind, prop_state_e state){ svn_ra_serf__xml_push_state(parser, state); if (state == PROPVAL) { prop_info_t *info; info = apr_pcalloc(parser->state->pool, sizeof(*info)); info->pool = parser->state->pool; parser->state->private = info; } return parser->state->private;}/* * Expat callback invoked on a start element tag for a PROPFIND response. */static svn_error_t *start_propfind(svn_ra_serf__xml_parser_t *parser, void *userData, svn_ra_serf__dav_props_t name, const char **attrs){ svn_ra_serf__propfind_context_t *ctx = userData; prop_state_e state; prop_info_t *info; state = parser->state->current_state; if (state == NONE && strcmp(name.name, "response") == 0) { svn_ra_serf__xml_push_state(parser, RESPONSE); } else if (state == RESPONSE && strcmp(name.name, "href") == 0) { info = push_state(parser, ctx, PROPVAL); info->ns = name.namespace; info->name = apr_pstrdup(info->pool, name.name); } else if (state == RESPONSE && strcmp(name.name, "prop") == 0) { push_state(parser, ctx, PROP); } else if (state == PROP) { info = push_state(parser, ctx, PROPVAL); info->ns = name.namespace; info->name = apr_pstrdup(info->pool, name.name); info->encoding = apr_pstrdup(info->pool, svn_ra_serf__find_attr(attrs, "V:encoding")); } return SVN_NO_ERROR;}/* * Expat callback invoked on an end element tag for a PROPFIND response. */static svn_error_t *end_propfind(svn_ra_serf__xml_parser_t *parser, void *userData, svn_ra_serf__dav_props_t name){ svn_ra_serf__propfind_context_t *ctx = userData; prop_state_e state; prop_info_t *info; state = parser->state->current_state; info = parser->state->private; if (state == RESPONSE && strcmp(name.name, "response") == 0) { svn_ra_serf__xml_pop_state(parser); } else if (state == PROP && strcmp(name.name, "prop") == 0) { svn_ra_serf__xml_pop_state(parser); } else if (state == PROPVAL) { const char *ns, *pname, *val; svn_string_t *val_str; /* if we didn't see a CDATA element, we may want the tag name * as long as it isn't equivalent to the property name. */ if (!info->val) { if (strcmp(info->name, name.name) != 0) { info->val = name.name; info->val_len = strlen(info->val); } else { info->val = ""; info->val_len = 0; } } if (parser->state->prev->current_state == RESPONSE && strcmp(name.name, "href") == 0) { if (strcmp(ctx->depth, "1") == 0) { ctx->current_path = svn_path_canonicalize(info->val, ctx->pool); } else { ctx->current_path = ctx->path; } } else if (info->encoding) { if (strcmp(info->encoding, "base64") == 0) { svn_string_t encoded; const svn_string_t *decoded; encoded.data = info->val; encoded.len = info->val_len; decoded = svn_base64_decode_string(&encoded, parser->state->pool); info->val = decoded->data; info->val_len = decoded->len; } else { abort(); } } ns = apr_pstrdup(ctx->pool, info->ns); pname = apr_pstrdup(ctx->pool, info->name); val = apr_pmemdup(ctx->pool, info->val, info->val_len); val_str = svn_string_ncreate(val, info->val_len, ctx->pool); /* set the return props and update our cache too. */ svn_ra_serf__set_ver_prop(ctx->ret_props, ctx->current_path, ctx->rev, ns, pname, val_str, ctx->pool); if (ctx->cache_props) { ns = apr_pstrdup(ctx->sess->pool, info->ns); pname = apr_pstrdup(ctx->sess->pool, info->name); val = apr_pmemdup(ctx->sess->pool, info->val, info->val_len); val_str = svn_string_ncreate(val, info->val_len, ctx->sess->pool); svn_ra_serf__set_ver_prop(ctx->sess->cached_props, ctx->current_path, ctx->rev, ns, pname, val_str, ctx->sess->pool); } svn_ra_serf__xml_pop_state(parser); } return SVN_NO_ERROR;}/* * Expat callback invoked on CDATA elements in a PROPFIND response. * * This callback can be called multiple times. */static svn_error_t *cdata_propfind(svn_ra_serf__xml_parser_t *parser, void *userData, const char *data, apr_size_t len){ svn_ra_serf__propfind_context_t *ctx = userData; prop_state_e state; prop_info_t *info; state = parser->state->current_state; info = parser->state->private; if (state == PROPVAL) { svn_ra_serf__expand_string(&info->val, &info->val_len, data, len, info->pool); } return SVN_NO_ERROR;}static apr_status_tsetup_propfind(serf_request_t *request, void *setup_baton, serf_bucket_t **req_bkt, serf_response_acceptor_t *acceptor,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -