props.c
来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,153 行 · 第 1/3 页
C
1,153 行
/*
* 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_delta.h"
#include "svn_ra.h"
#include "svn_path.h"
#include "svn_dav.h"
#include "svn_base64.h"
#include "svn_xml.h"
#include "svn_pools.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 },
{ 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 },
/* 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. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?