📄 mod_dav.c
字号:
/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. *//*** DAV extension module for Apache 2.0.***** This module is repository-independent. It depends on hooks provided by a** repository implementation.**** APACHE ISSUES:** - within a DAV hierarchy, if an unknown method is used and we default** to Apache's implementation, it sends back an OPTIONS with the wrong** set of methods -- there is NO HOOK for us.** therefore: we need to manually handle the HTTP_METHOD_NOT_ALLOWED** and HTTP_NOT_IMPLEMENTED responses (not ap_send_error_response).** - process_mkcol_body() had to dup code from ap_setup_client_block().** - it would be nice to get status lines from Apache for arbitrary** status codes** - it would be nice to be able to extend Apache's set of response** codes so that it doesn't return 500 when an unknown code is placed** into r->status.** - http_vhost functions should apply "const" to their params**** DESIGN NOTES:** - For PROPFIND, we batch up the entire response in memory before** sending it. We may want to reorganize around sending the information** as we suck it in from the propdb. Alternatively, we should at least** generate a total Content-Length if we're going to buffer in memory** so that we can keep the connection open.*/#include "apr_strings.h"#include "apr_lib.h" /* for apr_is* */#define APR_WANT_STRFUNC#include "apr_want.h"#include "httpd.h"#include "http_config.h"#include "http_core.h"#include "http_log.h"#include "http_main.h"#include "http_protocol.h"#include "http_request.h"#include "util_script.h"#include "mod_dav.h"/* ### what is the best way to set this? */#define DAV_DEFAULT_PROVIDER "filesystem"enum { DAV_ENABLED_UNSET = 0, DAV_ENABLED_OFF, DAV_ENABLED_ON};/* per-dir configuration */typedef struct { const char *provider_name; const dav_provider *provider; const char *dir; int locktimeout; int allow_depthinfinity; apr_table_t *d_params; /* per-directory DAV config parameters */} dav_dir_conf;/* per-server configuration */typedef struct { int unused;} dav_server_conf;#define DAV_INHERIT_VALUE(parent, child, field) \ ((child)->field ? (child)->field : (parent)->field)/* forward-declare for use in configuration lookup */extern module DAV_DECLARE_DATA dav_module;static void dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s){ /* DBG0("dav_init_handler"); */ ap_add_version_component(p, "DAV/2");}static void *dav_create_server_config(apr_pool_t *p, server_rec *s){ dav_server_conf *newconf; newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf)); /* ### this isn't used at the moment... */ return newconf;}static void *dav_merge_server_config(apr_pool_t *p, void *base, void *overrides){#if 0 dav_server_conf *child = overrides;#endif dav_server_conf *newconf; newconf = (dav_server_conf *) apr_pcalloc(p, sizeof(*newconf)); /* ### nothing to merge right now... */ return newconf;}static void *dav_create_dir_config(apr_pool_t *p, char *dir){ /* NOTE: dir==NULL creates the default per-dir config */ dav_dir_conf *conf; conf = (dav_dir_conf *) apr_pcalloc(p, sizeof(*conf)); /* clean up the directory to remove any trailing slash */ if (dir != NULL) { char *d; apr_size_t l; d = apr_pstrdup(p, dir); l = strlen(d); if (l > 1 && d[l - 1] == '/') d[l - 1] = '\0'; conf->dir = d; } conf->d_params = apr_table_make(p, 1); return conf;}static void *dav_merge_dir_config(apr_pool_t *p, void *base, void *overrides){ dav_dir_conf *parent = base; dav_dir_conf *child = overrides; dav_dir_conf *newconf = (dav_dir_conf *) apr_pcalloc(p, sizeof(*newconf)); /* DBG3("dav_merge_dir_config: new=%08lx base=%08lx overrides=%08lx", (long)newconf, (long)base, (long)overrides); */ newconf->provider_name = DAV_INHERIT_VALUE(parent, child, provider_name); newconf->provider = DAV_INHERIT_VALUE(parent, child, provider); if (parent->provider_name != NULL) { if (child->provider_name == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, "\"DAV Off\" cannot be used to turn off a subtree " "of a DAV-enabled location."); } else if (strcasecmp(child->provider_name, parent->provider_name) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, "A subtree cannot specify a different DAV provider " "than its parent."); } } newconf->locktimeout = DAV_INHERIT_VALUE(parent, child, locktimeout); newconf->dir = DAV_INHERIT_VALUE(parent, child, dir); newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child, allow_depthinfinity); newconf->d_params = apr_table_copy(p, parent->d_params); apr_table_overlap(newconf->d_params, child->d_params, APR_OVERLAP_TABLES_SET); return newconf;}apr_table_t *dav_get_dir_params(const request_rec *r){ dav_dir_conf *conf; conf = ap_get_module_config(r->per_dir_config, &dav_module); return conf->d_params;}static const dav_provider * dav_get_provider(request_rec *r){ dav_dir_conf *conf; conf = ap_get_module_config(r->per_dir_config, &dav_module); /* assert: conf->provider_name != NULL (otherwise, DAV is disabled, and we wouldn't be here) */ /* assert: conf->provider != NULL (checked when conf->provider_name is set) */ return conf->provider;}const dav_hooks_locks *dav_get_lock_hooks(request_rec *r){ return dav_get_provider(r)->locks;}const dav_hooks_propdb *dav_get_propdb_hooks(request_rec *r){ return dav_get_provider(r)->propdb;}const dav_hooks_vsn *dav_get_vsn_hooks(request_rec *r){ return dav_get_provider(r)->vsn;}const dav_hooks_binding *dav_get_binding_hooks(request_rec *r){ return dav_get_provider(r)->binding;}/* * Command handler for the DAV directive, which is TAKE1. */static const char *dav_cmd_dav(cmd_parms *cmd, void *config, const char *arg1){ dav_dir_conf *conf = (dav_dir_conf *) config; if (strcasecmp(arg1, "on") == 0) { conf->provider_name = DAV_DEFAULT_PROVIDER; } else if (strcasecmp(arg1, "off") == 0) { conf->provider_name = NULL; conf->provider = NULL; } else { conf->provider_name = apr_pstrdup(cmd->pool, arg1); } if (conf->provider_name != NULL) { /* lookup and cache the actual provider now */ conf->provider = dav_lookup_provider(conf->provider_name); if (conf->provider == NULL) { /* by the time they use it, the provider should be loaded and registered with us. */ return apr_psprintf(cmd->pool, "Unknown DAV provider: %s", conf->provider_name); } } return NULL;}/* * Command handler for the DAVDepthInfinity directive, which is FLAG. */static const char *dav_cmd_davdepthinfinity(cmd_parms *cmd, void *config, int arg){ dav_dir_conf *conf = (dav_dir_conf *) config; if (arg) conf->allow_depthinfinity = DAV_ENABLED_ON; else conf->allow_depthinfinity = DAV_ENABLED_OFF; return NULL;}/* * Command handler for DAVMinTimeout directive, which is TAKE1 */static const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config, const char *arg1){ dav_dir_conf *conf = (dav_dir_conf *) config; conf->locktimeout = atoi(arg1); if (conf->locktimeout < 0) return "DAVMinTimeout requires a non-negative integer."; return NULL;}/* * Command handler for DAVParam directive, which is TAKE2 */static const char *dav_cmd_davparam(cmd_parms *cmd, void *config, const char *arg1, const char *arg2){ dav_dir_conf *conf = (dav_dir_conf *) config; apr_table_set(conf->d_params, arg1, arg2); return NULL;}/*** dav_error_response()**** Send a nice response back to the user. In most cases, Apache doesn't** allow us to provide details in the body about what happened. This** function allows us to completely specify the response body.**** ### this function is not logging any errors! (e.g. the body)*/static int dav_error_response(request_rec *r, int status, const char *body){ r->status = status; r->status_line = ap_get_status_line(status); r->content_type = "text/html"; /* since we're returning DONE, ensure the request body is consumed. */ (void) ap_discard_request_body(r); /* begin the response now... */ ap_rvputs(r, DAV_RESPONSE_BODY_1, r->status_line, DAV_RESPONSE_BODY_2, &r->status_line[4], DAV_RESPONSE_BODY_3, NULL); ap_rputs(body, r); ap_rputs(ap_psignature("\n<P><HR>\n", r), r); ap_rputs(DAV_RESPONSE_BODY_4, 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; /* more work needed... sigh. */ /* ** Note: this is a teeny bit of overkill since we know there are no
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -