📄 mod_dav.c
字号:
apr_xml_quote_string(r->pool, err->desc, 0));
}
ap_rputs("</D:error>" DEBUG_CR, r);
/* the response has been sent. */
/*
* ### Use of DONE obviates logging..!
*/
return DONE;
}
/*
* Apache's URI escaping does not replace '&' since that is a valid character
* in a URI (to form a query section). We must explicitly handle it so that
* we can embed the URI into an XML document.
*/
static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri)
{
const char *e_uri = ap_escape_uri(p, uri);
/* check the easy case... */
if (ap_strchr_c(e_uri, '&') == NULL)
return e_uri;
/* there was a '&', so more work is needed... sigh. */
/*
* Note: this is a teeny bit of overkill since we know there are no
* '<' or '>' characters, but who cares.
*/
return apr_xml_quote_string(p, e_uri, 0);
}
/* Write a complete RESPONSE object out as a <DAV:repsonse> xml
element. Data is sent into brigade BB, which is auto-flushed into
OUTPUT filter stack. Use POOL for any temporary allocations.
[Presumably the <multistatus> tag has already been written; this
routine is shared by dav_send_multistatus and dav_stream_response.]
*/
static void dav_send_one_response(dav_response *response,
apr_bucket_brigade *bb,
ap_filter_t *output,
apr_pool_t *pool)
{
apr_text *t = NULL;
if (response->propresult.xmlns == NULL) {
ap_fputs(output, bb, "<D:response>");
}
else {
ap_fputs(output, bb, "<D:response");
for (t = response->propresult.xmlns; t; t = t->next) {
ap_fputs(output, bb, t->text);
}
ap_fputc(output, bb, '>');
}
ap_fputstrs(output, bb,
DEBUG_CR "<D:href>",
dav_xml_escape_uri(pool, response->href),
"</D:href>" DEBUG_CR,
NULL);
if (response->propresult.propstats == NULL) {
/* use the Status-Line text from Apache. Note, this will
* default to 500 Internal Server Error if first->status
* is not a known (or valid) status code.
*/
ap_fputstrs(output, bb,
"<D:status>HTTP/1.1 ",
ap_get_status_line(response->status),
"</D:status>" DEBUG_CR,
NULL);
}
else {
/* assume this includes <propstat> and is quoted properly */
for (t = response->propresult.propstats; t; t = t->next) {
ap_fputs(output, bb, t->text);
}
}
if (response->desc != NULL) {
/*
* We supply the description, so we know it doesn't have to
* have any escaping/encoding applied to it.
*/
ap_fputstrs(output, bb,
"<D:responsedescription>",
response->desc,
"</D:responsedescription>" DEBUG_CR,
NULL);
}
ap_fputs(output, bb, "</D:response>" DEBUG_CR);
}
/* Factorized helper function: prep request_rec R for a multistatus
response and write <multistatus> tag into BB, destined for
R->output_filters. Use xml NAMESPACES in initial tag, if
non-NULL. */
static void dav_begin_multistatus(apr_bucket_brigade *bb,
request_rec *r, int status,
apr_array_header_t *namespaces)
{
/* Set the correct status and Content-Type */
r->status = status;
ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
/* Send the headers and actual multistatus response now... */
ap_fputs(r->output_filters, bb, DAV_XML_HEADER DEBUG_CR
"<D:multistatus xmlns:D=\"DAV:\"");
if (namespaces != NULL) {
int i;
for (i = namespaces->nelts; i--; ) {
ap_fprintf(r->output_filters, bb, " xmlns:ns%d=\"%s\"", i,
APR_XML_GET_URI_ITEM(namespaces, i));
}
}
ap_fputs(r->output_filters, bb, ">" DEBUG_CR);
}
/* Finish a multistatus response started by dav_begin_multistatus: */
static apr_status_t dav_finish_multistatus(request_rec *r,
apr_bucket_brigade *bb)
{
apr_bucket *b;
ap_fputs(r->output_filters, bb, "</D:multistatus>" DEBUG_CR);
/* indicate the end of the response body */
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
/* deliver whatever might be remaining in the brigade */
return ap_pass_brigade(r->output_filters, bb);
}
static void dav_send_multistatus(request_rec *r, int status,
dav_response *first,
apr_array_header_t *namespaces)
{
apr_pool_t *subpool;
apr_bucket_brigade *bb = apr_brigade_create(r->pool,
r->connection->bucket_alloc);
dav_begin_multistatus(bb, r, status, namespaces);
apr_pool_create(&subpool, r->pool);
for (; first != NULL; first = first->next) {
apr_pool_clear(subpool);
dav_send_one_response(first, bb, r->output_filters, subpool);
}
apr_pool_destroy(subpool);
dav_finish_multistatus(r, bb);
}
/*
* dav_log_err()
*
* Write error information to the log.
*/
static void dav_log_err(request_rec *r, dav_error *err, int level)
{
dav_error *errscan;
/* Log the errors */
/* ### should have a directive to log the first or all */
for (errscan = err; errscan != NULL; errscan = errscan->prev) {
if (errscan->desc == NULL)
continue;
if (errscan->save_errno != 0) {
errno = errscan->save_errno;
ap_log_rerror(APLOG_MARK, level, errno, r, "%s [%d, #%d]",
errscan->desc, errscan->status, errscan->error_id);
}
else {
ap_log_rerror(APLOG_MARK, level, 0, r,
"%s [%d, #%d]",
errscan->desc, errscan->status, errscan->error_id);
}
}
}
/*
* dav_handle_err()
*
* Handle the standard error processing. <err> must be non-NULL.
*
* <response> is set by the following:
* - dav_validate_request()
* - dav_add_lock()
* - repos_hooks->remove_resource
* - repos_hooks->move_resource
* - repos_hooks->copy_resource
* - vsn_hooks->update
*/
static int dav_handle_err(request_rec *r, dav_error *err,
dav_response *response)
{
/* log the errors */
dav_log_err(r, err, APLOG_ERR);
if (response == NULL) {
dav_error *stackerr = err;
/* our error messages are safe; tell Apache this */
apr_table_setn(r->notes, "verbose-error-to", "*");
/* Didn't get a multistatus response passed in, but we still
might be able to generate a standard <D:error> response.
Search the error stack for an errortag. */
while (stackerr != NULL && stackerr->tagname == NULL)
stackerr = stackerr->prev;
if (stackerr != NULL && stackerr->tagname != NULL)
return dav_error_response_tag(r, stackerr);
return err->status;
}
/* send the multistatus and tell Apache the request/response is DONE. */
dav_send_multistatus(r, err->status, response, NULL);
return DONE;
}
/* handy function for return values of methods that (may) create things */
static int dav_created(request_rec *r, const char *locn, const char *what,
int replaced)
{
const char *body;
if (locn == NULL) {
locn = r->uri;
}
/* did the target resource already exist? */
if (replaced) {
/* Apache will supply a default message */
return HTTP_NO_CONTENT;
}
/* Per HTTP/1.1, S10.2.2: add a Location header to contain the
* URI that was created. */
/* Convert locn to an absolute URI, and return in Location header */
apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r));
/* ### insert an ETag header? see HTTP/1.1 S10.2.2 */
/* Apache doesn't allow us to set a variable body for HTTP_CREATED, so
* we must manufacture the entire response. */
body = apr_psprintf(r->pool, "%s %s has been created.",
what, ap_escape_html(r->pool, locn));
return dav_error_response(r, HTTP_CREATED, body);
}
/* ### move to dav_util? */
DAV_DECLARE(int) dav_get_depth(request_rec *r, int def_depth)
{
const char *depth = apr_table_get(r->headers_in, "Depth");
if (depth == NULL) {
return def_depth;
}
if (strcasecmp(depth, "infinity") == 0) {
return DAV_INFINITY;
}
else if (strcmp(depth, "0") == 0) {
return 0;
}
else if (strcmp(depth, "1") == 0) {
return 1;
}
/* The caller will return an HTTP_BAD_REQUEST. This will augment the
* default message that Apache provides. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"An invalid Depth header was specified.");
return -1;
}
static int dav_get_overwrite(request_rec *r)
{
const char *overwrite = apr_table_get(r->headers_in, "Overwrite");
if (overwrite == NULL) {
return 1; /* default is "T" */
}
if ((*overwrite == 'F' || *overwrite == 'f') && overwrite[1] == '\0') {
return 0;
}
if ((*overwrite == 'T' || *overwrite == 't') && overwrite[1] == '\0') {
return 1;
}
/* The caller will return an HTTP_BAD_REQUEST. This will augment the
* default message that Apache provides. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"An invalid Overwrite header was specified.");
return -1;
}
/* resolve a request URI to a resource descriptor.
*
* If label_allowed != 0, then allow the request target to be altered by
* a Label: header.
*
* If use_checked_in is true, then the repository provider should return
* the resource identified by the DAV:checked-in property of the resource
* identified by the Request-URI.
*/
static dav_error *dav_get_resource(request_rec *r, int label_allowed,
int use_checked_in, dav_resource **res_p)
{
dav_dir_conf *conf;
const char *label = NULL;
dav_error *err;
/* if the request target can be overridden, get any target selector */
if (label_allowed) {
label = apr_table_get(r->headers_in, "label");
}
conf = ap_get_module_config(r->per_dir_config, &dav_module);
/* assert: conf->provider != NULL */
/* resolve the resource */
err = (*conf->provider->repos->get_resource)(r, conf->dir,
label, use_checked_in,
res_p);
if (err != NULL) {
err = dav_push_error(r->pool, err->status, 0,
"Could not fetch resource information.", err);
return err;
}
/* Note: this shouldn't happen, but just be sure... */
if (*res_p == NULL) {
/* ### maybe use HTTP_INTERNAL_SERVER_ERROR */
return dav_new_error(r->pool, HTTP_NOT_FOUND, 0,
apr_psprintf(r->pool,
"The provider did not define a "
"resource for %s.",
ap_escape_html(r->pool, r->uri)));
}
/* ### hmm. this doesn't feel like the right place or thing to do */
/* if there were any input headers requiring a Vary header in the response,
* add it now */
dav_add_vary_header(r, r, *res_p);
return NULL;
}
static dav_error * dav_open_lockdb(request_rec *r, int ro, dav_lockdb **lockdb)
{
const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
if (hooks == NULL) {
*lockdb = NULL;
return NULL;
}
/* open the thing lazily */
return (*hooks->open_lockdb)(r, ro, 0, lockdb);
}
static int dav_parse_range(request_rec *r,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -