📄 util.c
字号:
/* * util.c : utility functions for the RA/DAV library * * ==================================================================== * 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>#define APR_WANT_STRFUNC#include <apr_want.h>#include <ne_socket.h>#include <ne_uri.h>#include <ne_compress.h>#include <ne_basic.h>#include "svn_pools.h"#include "svn_path.h"#include "svn_string.h"#include "svn_utf.h"#include "svn_xml.h"#include "svn_private_config.h"#include "ra_dav.h"#define WOOTWOOT 1typedef struct { apr_pool_t *pool; /* pool on which this is alloc-d */ void *original_userdata; /* userdata for callbacks */ const svn_ra_dav__xml_elm_t *elements; /* old-style elements table */ svn_ra_dav__xml_validate_cb *validate_cb; /* old-style validate callback */ svn_ra_dav__xml_startelm_cb *startelm_cb; /* old-style startelm callback */ svn_ra_dav__xml_endelm_cb *endelm_cb; /* old-style endelm callback */ svn_stringbuf_t *cdata_accum; /* stringbuffer for CDATA */} neon_shim_baton_t;const svn_ra_dav__xml_elm_t *svn_ra_dav__lookup_xml_elem(const svn_ra_dav__xml_elm_t *table, const char *nspace, const char *name){ /* placeholder for `unknown' element if it's present */ const svn_ra_dav__xml_elm_t *elem_unknown = NULL; const svn_ra_dav__xml_elm_t *elem; for(elem = table; elem->nspace; ++elem) { if (strcmp(elem->nspace, nspace) == 0 && strcmp(elem->name, name) == 0) return elem; /* Use a single loop to save CPU cycles. * * Maybe this element is defined as `unknown'? */ if (elem->id == ELEM_unknown) elem_unknown = elem; } /* ELEM_unknown position in the table or NULL */ return elem_unknown;}/** Fill in temporary structure for ELEM_unknown element. * * Call only for element ELEM_unknown! For Neon 0.23 API * compatibility, we need to fill the XML element structure with real * namespace and element name, as "old-style" handler used to get that * from Neon parser. This is a hack, so don't expect it to be elegant. * The @a elem_pointer is a reference to element pointer which is * returned by svn_ra_dav__lookup_xml_elem, and supposedly points at * en entry in the XML elements table supplied by an "old-style" * handler. @a elem_unknown_temporary is a reference to XML element * structure allocated on the stack. There's no reason to allocate it * anywhere else because it's going to use @a nspace and @a name which * are passed into the "new-style" handler by the Neon parser, so the * structure pointed at by @a elem_unknown_temporary must die when the * calling function completes. This function is designed to be called * from "new-style" startelm and endelm callbacks. */static voidhandle_unknown(const svn_ra_dav__xml_elm_t **elem_pointer, svn_ra_dav__xml_elm_t *elem_unknown_temporary, const char *nspace, const char *name){ elem_unknown_temporary->nspace = nspace; elem_unknown_temporary->name = name; elem_unknown_temporary->id = (*elem_pointer)->id; elem_unknown_temporary->flags = (*elem_pointer)->flags; /* The pointer will use temporary record instead of a table record */ *elem_pointer = elem_unknown_temporary;}/** (Neon 0.24) Start element parsing. * * Calls "old-style" API callbacks validate_cb and startelm_cb to emulate * Neon 0.23 parser. @a userdata is a @c neon_shim_baton_t instance. * ---- ne_xml.h ---- * The startelm callback may return: * <0 => abort the parse (NE_XML_ABORT) * 0 => decline this element (NE_XML_DECLINE) * >0 => accept this element; value is state for this element. * The 'parent' integer is the state returned by the handler of the * parent element. */static intshim_startelm(void *userdata, int parent_state, const char *nspace, const char *name, const char **attrs){ neon_shim_baton_t *baton = userdata; svn_ra_dav__xml_elm_t elem_unknown_temporary; const svn_ra_dav__xml_elm_t *elem = svn_ra_dav__lookup_xml_elem(baton->elements, nspace, name); int rc; if (!elem) return NE_XML_DECLINE; /* Let Neon handle this */ /* TODO: explore an option of keeping element pointer in the baton * to cut one loop in endelm */ /* 'parent' here actually means a parent element's id as opposed * to 'parent' parameter passed to the startelm() function */ rc = baton->validate_cb(baton->original_userdata, parent_state, elem->id); if (rc != SVN_RA_DAV__XML_VALID) { return (rc == SVN_RA_DAV__XML_DECLINE) ? NE_XML_DECLINE : NE_XML_ABORT; } if (elem->id == ELEM_unknown) handle_unknown(&elem, &elem_unknown_temporary, nspace, name); rc = baton->startelm_cb(baton->original_userdata, elem, attrs); if (rc != SVN_RA_DAV__XML_VALID) { return (rc == SVN_RA_DAV__XML_DECLINE) ? NE_XML_DECLINE : NE_XML_ABORT; } if (baton->cdata_accum != NULL) svn_stringbuf_setempty(baton->cdata_accum); else baton->cdata_accum = svn_stringbuf_create("", baton->pool); /* @a parent in the pre-Neon 0.24 interface was a parent's element * id but now it's the status returned by parent's startelm(), so we need to * bridge this by returning this element's id as a status. * We also need to ensure that element ids start with 1, because * zero is `decline'. See ra_dav.h definition of ELEM_* values. */ return elem->id;}/** (Neon 0.24) Collect element's contents. * * Collects element's contents into @a userdata string buffer. @a userdata is a * @c neon_shim_baton_t instance. * May return non-zero to abort the parse. */static int shim_cdata(void *userdata, int state, const char *cdata, size_t len){ const neon_shim_baton_t *baton = userdata; svn_stringbuf_appendbytes(baton->cdata_accum, cdata, len); return 0; /* no error */}/** (Neon 0.24) Finish parsing element. * * Calls "old-style" endelm_cb callback. @a userdata is a @c neon_shim_baton_t * instance. * May return non-zero to abort the parse. */static int shim_endelm(void *userdata, int state, const char *nspace, const char *name){ const neon_shim_baton_t *baton = userdata; svn_ra_dav__xml_elm_t elem_unknown_temporary; const svn_ra_dav__xml_elm_t *elem = svn_ra_dav__lookup_xml_elem(baton->elements, nspace, name); int rc; if (!elem) return -1; /* shouldn't be here if startelm didn't abort the parse */ if (elem->id == ELEM_unknown) handle_unknown(&elem, &elem_unknown_temporary, nspace, name); rc = baton->endelm_cb(baton->original_userdata, elem, baton->cdata_accum->data); if (rc != SVN_RA_DAV__XML_VALID) return -1; /* abort the parse */ return 0; /* no error */}/** Push an XML handler onto Neon's handler stack. * * Parser @a p uses a stack of handlers to process XML. The handler is * composed of validation callback @a validate_cb, start-element * callback @a startelm_cb, and end-element callback @a endelm_cb, which * collectively handle elements supplied in an array @a elements. Parser * passes given user baton @a userdata to all callbacks. * This is a new function on top of ne_xml_push_handler, adds memory pool * @a pool as the last parameter. This parameter is not used with Neon * 0.23.9, but will be with Neon 0.24. When Neon 0.24 is used, ra_dav * receives calls from the new interface and performs functions described * above by itself, using @a elements and calling callbacks according to * 0.23 interface. */static void shim_xml_push_handler(ne_xml_parser *p, const svn_ra_dav__xml_elm_t *elements, svn_ra_dav__xml_validate_cb validate_cb, svn_ra_dav__xml_startelm_cb startelm_cb, svn_ra_dav__xml_endelm_cb endelm_cb, void *userdata, apr_pool_t *pool){ neon_shim_baton_t *baton = apr_pcalloc(pool, sizeof(neon_shim_baton_t)); baton->pool = pool; baton->original_userdata = userdata; baton->elements = elements; baton->validate_cb = validate_cb; baton->startelm_cb = startelm_cb; baton->endelm_cb = endelm_cb; baton->cdata_accum = NULL; /* don't create until startelm is called */ ne_xml_push_handler(p, shim_startelm, shim_cdata, shim_endelm, baton);}void svn_ra_dav__copy_href(svn_stringbuf_t *dst, const char *src){ ne_uri parsed_url; /* parse the PATH element out of the URL and store it. ### do we want to verify the rest matches the current session? 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(src, &parsed_url); svn_stringbuf_set(dst, parsed_url.path); ne_uri_free(&parsed_url);}svn_error_t *svn_ra_dav__convert_error(ne_session *sess, const char *context, int retcode, apr_pool_t *pool){ int errcode = SVN_ERR_RA_DAV_REQUEST_FAILED; const char *msg; const char *hostport; /* Convert the return codes. */ switch (retcode) { case NE_AUTH: errcode = SVN_ERR_RA_NOT_AUTHORIZED; msg = _("authorization failed"); break; case NE_CONNECT: msg = _("could not connect to server"); break; case NE_TIMEOUT: msg = _("timed out waiting for server"); break; default: /* Get the error string from neon and convert to UTF-8. */ SVN_ERR(svn_utf_cstring_to_utf8(&msg, ne_get_error(sess), pool)); break; } /* The hostname may contain non-ASCII characters, so convert it to UTF-8. */ SVN_ERR(svn_utf_cstring_to_utf8(&hostport, ne_get_server_hostport(sess), pool)); return svn_error_createf(errcode, NULL, "%s: %s (%s://%s)", context, msg, ne_get_scheme(sess), hostport);}/** Error parsing **//* Custom function of type ne_accept_response. */static int ra_dav_error_accepter(void *userdata, ne_request *req, const ne_status *st){ /* Before, this function was being run for *all* responses including the 401 auth challenge. In neon 0.24.x that was harmless. But in neon 0.25.0, trying to parse a 401 response as XML using ne_xml_parse_v aborts the response; so the auth hooks never got a chance. */#ifdef SVN_NEON_0_25 ne_content_type ctype; /* Only accept non-2xx responses with text/xml content-type */ if (st->klass != 2 && ne_get_content_type(req, &ctype) == 0) { int is_xml = (strcmp(ctype.type, "text") == 0 && strcmp(ctype.subtype, "xml") == 0); ne_free(ctype.value); return is_xml; } else return 0;#else /* ! SVN_NEON_0_25 */ /* Only accept the body-response if the HTTP status code is *not* 2XX. */ return (st->klass != 2);#endif /* if/else SVN_NEON_0_25 */}static const svn_ra_dav__xml_elm_t error_elements[] ={ { "DAV:", "error", ELEM_error, 0 }, { "svn:", "error", ELEM_svn_error, 0 }, { "http://apache.org/dav/xmlns", "human-readable",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -