📄 util.c
字号:
ELEM_human_readable, SVN_RA_DAV__XML_CDATA }, /* ### our validator doesn't yet recognize the rich, specific <D:some-condition-failed/> objects as defined by DeltaV.*/ { NULL }};static int validate_error_elements(void *userdata, svn_ra_dav__xml_elmid parent, svn_ra_dav__xml_elmid child){ switch (parent) { case ELEM_root: if (child == ELEM_error) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_INVALID; case ELEM_error: if (child == ELEM_svn_error || child == ELEM_human_readable) return SVN_RA_DAV__XML_VALID; else return SVN_RA_DAV__XML_DECLINE; /* ignore if something else was in there */ default: return SVN_RA_DAV__XML_DECLINE; } /* NOTREACHED */}static int start_err_element(void *userdata, const svn_ra_dav__xml_elm_t *elm, const char **atts){ svn_error_t **err = userdata; switch (elm->id) { case ELEM_svn_error: { /* allocate the svn_error_t. Hopefully the value will be overwritten by the <human-readable> tag, or even someday by a <D:failed-precondition/> tag. */ *err = svn_error_create(APR_EGENERAL, NULL, "General svn error from server"); break; } case ELEM_human_readable: { /* get the errorcode attribute if present */ const char *errcode_str = svn_xml_get_attr_value("errcode", /* ### make constant in some mod_dav header? */ atts); if (errcode_str && *err) (*err)->apr_err = atoi(errcode_str); break; } default: break; } return SVN_RA_DAV__XML_VALID;}static int end_err_element(void *userdata, const svn_ra_dav__xml_elm_t *elm, const char *cdata){ svn_error_t **err = userdata; switch (elm->id) { case ELEM_human_readable: { if (cdata && *err) { /* On the server dav_error_response_tag() will add a leading and trailing newline if DEBUG_CR is defined in mod_dav.h, so remove any such characters here. */ apr_size_t len; if (*cdata == '\n') ++cdata; len = strlen(cdata); if (len > 0 && cdata[len-1] == '\n') --len; (*err)->message = apr_pstrmemdup((*err)->pool, cdata, len); } break; } default: break; } return SVN_RA_DAV__XML_VALID;}/* A body provider for ne_set_request_body_provider that pulls data * from an APR file. See ne_request.h for a description of the * interface. */static ssize_t ra_dav_body_provider(void *userdata, char *buffer, size_t buflen){ apr_file_t *body_file = userdata; apr_status_t status; if (buflen == 0) { /* This is the beginning of a new body pull. Rewind the file. */ apr_off_t offset = 0; status = apr_file_seek(body_file, APR_SET, &offset); return (status ? -1 : 0); } else { apr_size_t nbytes = buflen; status = apr_file_read(body_file, buffer, &nbytes); if (status) return (APR_STATUS_IS_EOF(status) ? 0 : -1); else return nbytes; }}svn_error_t *svn_ra_dav__set_neon_body_provider(ne_request *req, apr_file_t *body_file){ apr_status_t status; apr_finfo_t finfo; /* ### APR bug? apr_file_info_get won't always return the correct size for buffered files. */ status = apr_file_info_get(&finfo, APR_FINFO_SIZE, body_file); if (status) return svn_error_wrap_apr(status, _("Can't calculate the request body size")); ne_set_request_body_provider(req, (size_t) finfo.size, ra_dav_body_provider, body_file); return SVN_NO_ERROR;}typedef struct spool_reader_baton_t{ const char *spool_file_name; apr_file_t *spool_file; apr_pool_t *pool; svn_error_t *error;} spool_reader_baton_t;/* This implements the ne_block_reader() callback interface. */#ifdef SVN_NEON_0_25static int#else /* ! SVN_NEON_0_25 */static void#endif /* if/else SVN_NEON_0_25 */spool_reader(void *userdata, const char *buf, size_t len){ spool_reader_baton_t *baton = userdata; if (! baton->error) baton->error = svn_io_file_write_full(baton->spool_file, buf, len, NULL, baton->pool);#ifdef SVN_NEON_0_25 if (baton->error) /* ### Call ne_set_error(), as ne_block_reader doc implies? */ return 1; else return 0;#endif /* SVN_NEON_0_25 */}static svn_error_t *parse_spool_file(const char *spool_file_name, ne_xml_parser *success_parser, apr_pool_t *pool){ apr_file_t *spool_file; svn_stream_t *spool_stream; char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); apr_size_t len; SVN_ERR(svn_io_file_open(&spool_file, spool_file_name, (APR_READ | APR_BUFFERED), APR_OS_DEFAULT, pool)); spool_stream = svn_stream_from_aprfile(spool_file, pool); while (1) { len = SVN__STREAM_CHUNK_SIZE; SVN_ERR(svn_stream_read(spool_stream, buf, &len)); if (len > 0) ne_xml_parse(success_parser, buf, len); if (len != SVN__STREAM_CHUNK_SIZE) break; } return SVN_NO_ERROR;}/* See doc string for svn_ra_dav__parsed_request. The only new parameter here is use_neon_shim, which if true, means that VALIDATE_CB, STARTELM_CB, and ENDELM_CB are expecting the old, pre-0.24 Neon api, so use a shim layer to translate for them. */static svn_error_t *parsed_request(ne_session *sess, const char *method, const char *url, const char *body, apr_file_t *body_file, void set_parser(ne_xml_parser *parser, void *baton), const svn_ra_dav__xml_elm_t *elements, svn_boolean_t use_neon_shim, /* These three are defined iff use_neon_shim is defined. */ svn_ra_dav__xml_validate_cb validate_compat_cb, svn_ra_dav__xml_startelm_cb startelm_compat_cb, svn_ra_dav__xml_endelm_cb endelm_compat_cb, /* These three are defined iff use_neon_shim is NOT defined. */ ne_xml_startelm_cb *startelm_cb, ne_xml_cdata_cb *cdata_cb, ne_xml_endelm_cb *endelm_cb, void *baton, apr_hash_t *extra_headers, int *status_code, svn_boolean_t spool_response, apr_pool_t *pool){ ne_request *req = NULL; ne_decompress *decompress_main = NULL; ne_decompress *decompress_err = NULL; ne_xml_parser *success_parser = NULL; ne_xml_parser *error_parser = NULL; int rv;#ifndef SVN_NEON_0_25 int decompress_rv;#endif /* ! SVN_NEON_0_25 */ int code; int expected_code; const char *msg; spool_reader_baton_t spool_reader_baton; svn_error_t *err = SVN_NO_ERROR; svn_ra_dav__session_t *ras = ne_get_session_private(sess, SVN_RA_NE_SESSION_ID); /* create/prep the request */ req = ne_request_create(sess, method, url); if (body != NULL) ne_set_request_body_buffer(req, body, strlen(body)); else if ((err = svn_ra_dav__set_neon_body_provider(req, body_file))) goto cleanup; /* ### use a symbolic name somewhere for this MIME type? */ ne_add_request_header(req, "Content-Type", "text/xml"); /* add any extra headers passed in by caller. */ if (extra_headers != NULL) { apr_hash_index_t *hi; for (hi = apr_hash_first(pool, extra_headers); hi; hi = apr_hash_next(hi)) { const void *key; void *val; apr_hash_this(hi, &key, NULL, &val); ne_add_request_header(req, (const char *) key, (const char *) val); } } /* create a parser to read the normal response body */ success_parser = ne_xml_create(); if (use_neon_shim) { shim_xml_push_handler(success_parser, elements, validate_compat_cb, startelm_compat_cb, endelm_compat_cb, baton, pool); } else { ne_xml_push_handler(success_parser, startelm_cb, cdata_cb, endelm_cb, baton); } /* ### HACK: Set the parser's error to the empty string. Someday we hope neon will let us have an easy way to tell the difference between XML parsing errors, and errors that occur while handling the XML tags that we get. Until then, trust that whenever neon has an error somewhere below the API, it sets its own error to something non-empty (the API promises non-NULL, at least). */ ne_xml_set_error(success_parser, ""); /* if our caller is interested in having access to this parser, call the SET_PARSER callback with BATON. */ if (set_parser != NULL) set_parser(success_parser, baton); /* create a parser to read the <D:error> response body */ error_parser = ne_xml_create(); /* ### The error callbacks are local to this file and are still ### using the Neon <= 0.23 API. They need to be upgraded. In ### the meantime, we ignore the value of use_neon_shim here. */ shim_xml_push_handler(error_parser, error_elements, validate_error_elements, start_err_element, end_err_element, &err, pool); /* Register the "main" accepter and body-reader with the request -- the one to use when the HTTP status is 2XX. If we are spooling the response to disk first, we use our custom spool reader. */ if (spool_response) { const char *tmpfile_path; err = svn_io_temp_dir(&tmpfile_path, pool); if (err) goto cleanup; tmpfile_path = svn_path_join(tmpfile_path, "dav-spool", pool); err = svn_io_open_unique_file2(&spool_reader_baton.spool_file,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -