📄 props.c
字号:
/* * props.c : routines for fetching DAV properties * * ==================================================================== * Copyright (c) 2000-2004 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 <apr_pools.h>#include <apr_tables.h>#include <apr_strings.h>#define APR_WANT_STRFUNC#include <apr_want.h>#include <ne_socket.h>#include <ne_basic.h>#include <ne_props.h>#include <ne_xml.h>#include "svn_error.h"#include "svn_path.h"#include "svn_dav.h"#include "svn_base64.h"#include "svn_xml.h"#include "svn_time.h"#include "svn_pools.h"#include "svn_props.h"#include "../libsvn_ra/ra_loader.h"#include "svn_private_config.h"#include "ra_dav.h"/* some definitions of various properties that may be fetched */const ne_propname svn_ra_dav__vcc_prop = { "DAV:", "version-controlled-configuration"};const ne_propname svn_ra_dav__checked_in_prop = { "DAV:", "checked-in"};/* when we begin a checkout, we fetch these from the "public" resources to steer us towards a Baseline Collection. we fetch the resourcetype to verify that we're accessing a collection. */static const ne_propname starting_props[] ={ { "DAV:", "version-controlled-configuration" }, { "DAV:", "resourcetype" }, { SVN_DAV_PROP_NS_DAV, "baseline-relative-path" }, { SVN_DAV_PROP_NS_DAV, "repository-uuid"}, { NULL }};/* when speaking to a Baseline to reach the Baseline Collection, fetch these properties. */static const ne_propname baseline_props[] ={ { "DAV:", "baseline-collection" }, { "DAV:", "version-name" }, { NULL }};/*** Propfind Implementation ***/typedef struct { svn_ra_dav__xml_elmid id; const char *name; int is_property; /* is it a property, or part of some structure? */} elem_defn;static const elem_defn elem_definitions[] ={ /*** NOTE: Make sure that every item in here is also represented in propfind_elements[] ***/ /* DAV elements */ { ELEM_multistatus, "DAV:multistatus", 0 }, { ELEM_response, "DAV:response", 0 }, { ELEM_href, "DAV:href", SVN_RA_DAV__XML_CDATA }, { ELEM_propstat, "DAV:propstat", 0 }, { ELEM_prop, "DAV:prop", 0 }, { ELEM_status, "DAV:status", SVN_RA_DAV__XML_CDATA }, { ELEM_baseline, "DAV:baseline", SVN_RA_DAV__XML_CDATA }, { ELEM_collection, "DAV:collection", SVN_RA_DAV__XML_CDATA }, { ELEM_resourcetype, "DAV:resourcetype", 0 }, { ELEM_baseline_coll, SVN_RA_DAV__PROP_BASELINE_COLLECTION, 0 }, { ELEM_checked_in, SVN_RA_DAV__PROP_CHECKED_IN, 0 }, { ELEM_vcc, SVN_RA_DAV__PROP_VCC, 0 }, { ELEM_version_name, SVN_RA_DAV__PROP_VERSION_NAME, 1 }, { ELEM_get_content_length, SVN_RA_DAV__PROP_GETCONTENTLENGTH, 1 }, { ELEM_creationdate, SVN_RA_DAV__PROP_CREATIONDATE, 1 }, { ELEM_creator_displayname, SVN_RA_DAV__PROP_CREATOR_DISPLAYNAME, 1 }, /* SVN elements */ { ELEM_baseline_relpath, SVN_RA_DAV__PROP_BASELINE_RELPATH, 1 }, { ELEM_md5_checksum, SVN_RA_DAV__PROP_MD5_CHECKSUM, 1 }, { ELEM_repository_uuid, SVN_RA_DAV__PROP_REPOSITORY_UUID, 1 }, { ELEM_deadprop_count, SVN_RA_DAV__PROP_DEADPROP_COUNT, 1 }, { 0 }};static const svn_ra_dav__xml_elm_t propfind_elements[] = { /*** NOTE: Make sure that every item in here is also represented in elem_definitions[] ***/ /* DAV elements */ { "DAV:", "multistatus", ELEM_multistatus, 0 }, { "DAV:", "response", ELEM_response, 0 }, { "DAV:", "href", ELEM_href, SVN_RA_DAV__XML_CDATA }, { "DAV:", "propstat", ELEM_propstat, 0 }, { "DAV:", "prop", ELEM_prop, 0 }, { "DAV:", "status", ELEM_status, SVN_RA_DAV__XML_CDATA }, { "DAV:", "baseline", ELEM_baseline, SVN_RA_DAV__XML_CDATA }, { "DAV:", "baseline-collection", ELEM_baseline_coll, SVN_RA_DAV__XML_CDATA }, { "DAV:", "checked-in", ELEM_checked_in, 0 }, { "DAV:", "collection", ELEM_collection, SVN_RA_DAV__XML_CDATA }, { "DAV:", "resourcetype", ELEM_resourcetype, 0 }, { "DAV:", "version-controlled-configuration", ELEM_vcc, 0 }, { "DAV:", "version-name", ELEM_version_name, SVN_RA_DAV__XML_CDATA }, { "DAV:", "getcontentlength", ELEM_get_content_length, SVN_RA_DAV__XML_CDATA }, { "DAV:", "creationdate", ELEM_creationdate, SVN_RA_DAV__XML_CDATA }, { "DAV:", "creator-displayname", ELEM_creator_displayname, SVN_RA_DAV__XML_CDATA }, /* SVN elements */ { SVN_DAV_PROP_NS_DAV, "baseline-relative-path", ELEM_baseline_relpath, SVN_RA_DAV__XML_CDATA }, { SVN_DAV_PROP_NS_DAV, "md5-checksum", ELEM_md5_checksum, SVN_RA_DAV__XML_CDATA }, { SVN_DAV_PROP_NS_DAV, "repository-uuid", ELEM_repository_uuid, SVN_RA_DAV__XML_CDATA }, { SVN_DAV_PROP_NS_DAV, "deadprop-count", ELEM_deadprop_count, SVN_RA_DAV__XML_CDATA }, /* Unknowns */ { "", "", ELEM_unknown, SVN_RA_DAV__XML_COLLECT }, { NULL } };typedef struct propfind_ctx_t{ apr_hash_t *props; /* const char *URL-PATH -> svn_ra_dav_resource_t */ svn_ra_dav_resource_t *rsrc; /* the current resource. */ const char *encoding; /* property encoding (or NULL) */ int status; /* status for the current <propstat> (or 0 if unknown). */ apr_hash_t *propbuffer; /* holds properties until their status is known. */ svn_ra_dav__xml_elmid last_open_id; /* the id of the last opened tag. */ ne_xml_parser *parser; /* xml parser handling the PROPSET request. */ apr_pool_t *pool;} propfind_ctx_t;/* Look up an element definition ID. May return NULL if the elem is not recognized. */static const elem_defn *defn_from_id(svn_ra_dav__xml_elmid id){ const elem_defn *defn; for (defn = elem_definitions; defn->name != NULL; ++defn) { if (id == defn->id) return defn; } return NULL;}/* Assign URL to RSRC. Use POOL for any allocations. */static void assign_rsrc_url(svn_ra_dav_resource_t *rsrc, const char *url, apr_pool_t *pool){ char *url_path; apr_size_t len; ne_uri parsed_url; /* Parse the PATH element out of the URL. NOTE: mod_dav does not (currently) use an absolute URL, but simply a server-relative path (i.e. this uri_parse is effectively a no-op). */ (void) ne_uri_parse(url, &parsed_url); url_path = apr_pstrdup(pool, parsed_url.path); ne_uri_free(&parsed_url); /* Clean up trailing slashes from the URL. */ len = strlen(url_path); if (len > 1 && url_path[len - 1] == '/') url_path[len - 1] = '\0'; rsrc->url = url_path;}static int validate_element(void *userdata, svn_ra_dav__xml_elmid parent, svn_ra_dav__xml_elmid child){ switch (parent) { case ELEM_root: if (child == ELEM_multistatus) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_INVALID; case ELEM_multistatus: if (child == ELEM_response) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_DECLINE; case ELEM_response: if ((child == ELEM_href) || (child == ELEM_propstat)) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_DECLINE; case ELEM_propstat: if ((child == ELEM_prop) || (child == ELEM_status)) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_DECLINE; case ELEM_prop: return SVN_RA_DAV__XML_VALID; /* handle all children of <prop> */ case ELEM_baseline_coll: case ELEM_checked_in: case ELEM_vcc: if (child == ELEM_href) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_DECLINE; /* not concerned with other types */ case ELEM_resourcetype: if ((child == ELEM_collection) || (child == ELEM_baseline)) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_DECLINE; /* not concerned with other types (### now) */ default: return SVN_RA_DAV__XML_DECLINE; } /* NOTREACHED */}static int start_element(void *userdata, const svn_ra_dav__xml_elm_t *elm, const char **atts){ propfind_ctx_t *pc = userdata; switch (elm->id) { case ELEM_response: if (pc->rsrc) return SVN_RA_DAV__XML_INVALID; /* Create a new resource. */ pc->rsrc = apr_pcalloc(pc->pool, sizeof(*(pc->rsrc))); pc->rsrc->pool = pc->pool; pc->rsrc->propset = apr_hash_make(pc->pool); pc->status = 0; break; case ELEM_propstat: pc->status = 0; break; case ELEM_href: /* Remember this <href>'s parent so that when we close this tag, we know to whom the URL assignment belongs. Could be the resource itself, or one of the properties: ELEM_baseline_coll, ELEM_checked_in, ELEM_vcc: */ pc->rsrc->href_parent = pc->last_open_id; break; case ELEM_collection: pc->rsrc->is_collection = 1; break; case ELEM_unknown: /* these are our user-visible properties, presumably. */ pc->encoding = ne_xml_get_attr(pc->parser, atts, SVN_DAV_PROP_NS_DAV, "encoding"); if (pc->encoding) pc->encoding = apr_pstrdup(pc->pool, pc->encoding); break; default: /* nothing to do for these */ break; } /* Remember the last tag we opened. */ pc->last_open_id = elm->id; return SVN_RA_DAV__XML_VALID;}static int end_element(void *userdata, const svn_ra_dav__xml_elm_t *elm, const char *cdata){ propfind_ctx_t *pc = userdata; svn_ra_dav_resource_t *rsrc = pc->rsrc; const char *name; const svn_string_t *value = NULL; const elem_defn *parent_defn; const elem_defn *defn; ne_status status; switch (elm->id) { case ELEM_response: /* Verify that we've received a URL for this resource. */ if (!pc->rsrc->url) return SVN_RA_DAV__XML_INVALID; /* Store the resource in the top-level hash table. */ apr_hash_set(pc->props, pc->rsrc->url, APR_HASH_KEY_STRING, pc->rsrc); pc->rsrc = NULL; return SVN_RA_DAV__XML_VALID; case ELEM_propstat: /* We're at the end of a set of properties. Do the right thing status-wise. */ if (pc->status) { /* We have a status. Loop over the buffered properties, and if the status is a good one (200), copy them into the resources's property hash. Regardless of the status, we'll be removing these from the temporary buffer as we go along. */ apr_hash_index_t *hi = apr_hash_first(pc->pool, pc->propbuffer); for (; hi; hi = apr_hash_next(hi)) { const void *key; apr_ssize_t klen; void *val; apr_hash_this(hi, &key, &klen, &val); if (pc->status == 200) apr_hash_set(rsrc->propset, key, klen, val); apr_hash_set(pc->propbuffer, key, klen, NULL); } } else if (! pc->status) { /* No status at all? Bogosity. */ return SVN_RA_DAV__XML_INVALID; } return SVN_RA_DAV__XML_VALID; case ELEM_status: /* Parse the <status> tag's CDATA for a status code. */ if (ne_parse_statusline(cdata, &status)) return SVN_RA_DAV__XML_INVALID; free(status.reason_phrase); pc->status = status.code; return SVN_RA_DAV__XML_VALID; case ELEM_href: /* Special handling for <href> that belongs to the <response> tag. */ if (rsrc->href_parent == ELEM_response) { assign_rsrc_url(pc->rsrc, cdata, pc->pool); return SVN_RA_DAV__XML_VALID; } /* Use the parent element's name, not the href. */ parent_defn = defn_from_id(rsrc->href_parent); /* No known parent? Get outta here. */ if (!parent_defn) return SVN_RA_DAV__XML_VALID; /* All other href's we'll treat as property values. */ name = parent_defn->name; value = svn_string_create(cdata, pc->pool); break; default: /*** This case is, as usual, for everything not covered by other cases. ELM->id should be either ELEM_unknown, or one of the ids in the elem_definitions[] structure. In this case, we seek to handle properties. Since ELEM_unknown should only occur for properties, we will handle that id. All other ids will be searched for in the elem_definitions[] structure to determine if they are properties. Properties, we handle; all else hits the road. ***/ if (elm->id == ELEM_unknown) { name = apr_pstrcat(pc->pool, elm->nspace, elm->name, NULL); } else { defn = defn_from_id(elm->id); if (! (defn && defn->is_property)) return SVN_RA_DAV__XML_VALID; name = defn->name; } /* Check for encoding attribute. */ if (pc->encoding == NULL) { /* Handle the property value by converting it to string. */ value = svn_string_create(cdata, pc->pool); break; } /* Check for known encoding type */ if (strcmp(pc->encoding, "base64") != 0) return SVN_RA_DAV__XML_INVALID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -