📄 util.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.*** - various utilities, repository-independent*/#include "apr_strings.h"#include "apr_lib.h"#define APR_WANT_STRFUNC#include "apr_want.h"#include "mod_dav.h"#include "http_request.h"#include "http_config.h"#include "http_vhost.h"#include "http_log.h"#include "http_protocol.h"DAV_DECLARE(dav_error*) dav_new_error(apr_pool_t *p, int status, int error_id, const char *desc){ int save_errno = errno; dav_error *err = apr_pcalloc(p, sizeof(*err)); /* DBG3("dav_new_error: %d %d %s", status, error_id, desc ? desc : "(no desc)"); */ err->status = status; err->error_id = error_id; err->desc = desc; err->save_errno = save_errno; return err;}DAV_DECLARE(dav_error*) dav_push_error(apr_pool_t *p, int status, int error_id, const char *desc, dav_error *prev){ dav_error *err = apr_pcalloc(p, sizeof(*err)); err->status = status; err->error_id = error_id; err->desc = desc; err->prev = prev; return err;}DAV_DECLARE(void) dav_check_bufsize(apr_pool_t * p, dav_buffer *pbuf, apr_size_t extra_needed){ /* grow the buffer if necessary */ if (pbuf->cur_len + extra_needed > pbuf->alloc_len) { char *newbuf; pbuf->alloc_len += extra_needed + DAV_BUFFER_PAD; newbuf = apr_palloc(p, pbuf->alloc_len); memcpy(newbuf, pbuf->buf, pbuf->cur_len); pbuf->buf = newbuf; }}DAV_DECLARE(void) dav_set_bufsize(apr_pool_t * p, dav_buffer *pbuf, apr_size_t size){ /* NOTE: this does not retain prior contents */ /* NOTE: this function is used to init the first pointer, too, since the PAD will be larger than alloc_len (0) for zeroed structures */ /* grow if we don't have enough for the requested size plus padding */ if (size + DAV_BUFFER_PAD > pbuf->alloc_len) { /* set the new length; min of MINSIZE */ pbuf->alloc_len = size + DAV_BUFFER_PAD; if (pbuf->alloc_len < DAV_BUFFER_MINSIZE) pbuf->alloc_len = DAV_BUFFER_MINSIZE; pbuf->buf = apr_palloc(p, pbuf->alloc_len); } pbuf->cur_len = size;}/* initialize a buffer and copy the specified (null-term'd) string into it */DAV_DECLARE(void) dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, const char *str){ dav_set_bufsize(p, pbuf, strlen(str)); memcpy(pbuf->buf, str, pbuf->cur_len + 1);}/* append a string to the end of the buffer, adjust length */DAV_DECLARE(void) dav_buffer_append(apr_pool_t *p, dav_buffer *pbuf, const char *str){ size_t len = strlen(str); dav_check_bufsize(p, pbuf, len + 1); memcpy(pbuf->buf + pbuf->cur_len, str, len + 1); pbuf->cur_len += len;}/* place a string on the end of the buffer, do NOT adjust length */DAV_DECLARE(void) dav_buffer_place(apr_pool_t *p, dav_buffer *pbuf, const char *str){ size_t len = strlen(str); dav_check_bufsize(p, pbuf, len + 1); memcpy(pbuf->buf + pbuf->cur_len, str, len + 1);}/* place some memory on the end of a buffer; do NOT adjust length */DAV_DECLARE(void) dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf, const void *mem, apr_size_t amt, apr_size_t pad){ dav_check_bufsize(p, pbuf, amt + pad); memcpy(pbuf->buf + pbuf->cur_len, mem, amt);}/*** dav_lookup_uri()**** Extension for ap_sub_req_lookup_uri() which can't handle absolute** URIs properly.**** If NULL is returned, then an error occurred with parsing the URI or** the URI does not match the current server.*/dav_lookup_result dav_lookup_uri(const char *uri, request_rec * r){ dav_lookup_result result = { 0 }; const char *scheme; apr_port_t port; uri_components comp; char *new_file; const char *domain; /* first thing to do is parse the URI into various components */ if (ap_parse_uri_components(r->pool, uri, &comp) != HTTP_OK) { result.err.status = HTTP_BAD_REQUEST; result.err.desc = "Invalid syntax in Destination URI."; return result; } /* the URI must be an absoluteURI (WEBDAV S9.3) */ if (comp.scheme == NULL) { result.err.status = HTTP_BAD_REQUEST; result.err.desc = "Destination URI must be an absolute URI."; return result; } /* ### not sure this works if the current request came in via https: */ scheme = r->parsed_uri.scheme; if (scheme == NULL) scheme = ap_http_method(r); /* insert a port if the URI did not contain one */ if (comp.port == 0) comp.port = ap_default_port_for_scheme(comp.scheme); /* now, verify that the URI uses the same scheme as the current request. the port, must match our port. the URI must not have a query (args) or a fragment */ apr_sockaddr_port_get(&port, r->connection->local_addr); if (strcasecmp(comp.scheme, scheme) != 0 || comp.port != port) { result.err.status = HTTP_BAD_GATEWAY; result.err.desc = apr_psprintf(r->pool, "Destination URI refers to different " "scheme or port (%s://hostname:%d)" APR_EOL_STR "(want: %s://hostname:%d)", comp.scheme ? comp.scheme : scheme, comp.port ? comp.port : port, scheme, port); return result; } if (comp.query != NULL || comp.fragment != NULL) { result.err.status = HTTP_BAD_REQUEST; result.err.desc = "Destination URI contains invalid components " "(a query or a fragment)."; return result; } /* we have verified the scheme, port, and general structure */ /* ** Hrm. IE5 will pass unqualified hostnames for both the ** Host: and Destination: headers. This breaks the ** http_vhost.c::matches_aliases function. ** ** For now, qualify unqualified comp.hostnames with ** r->server->server_hostname. ** ** ### this is a big hack. Apache should provide a better way. ** ### maybe the admin should list the unqualified hosts in a ** ### <ServerAlias> block? */ if (strrchr(comp.hostname, '.') == NULL && (domain = strchr(r->server->server_hostname, '.')) != NULL) { comp.hostname = apr_pstrcat(r->pool, comp.hostname, domain, NULL); } /* now, if a hostname was provided, then verify that it represents the same server as the current connection. note that we just use our port, since we've verified the URI matches ours */ if (comp.hostname != NULL && !ap_matches_request_vhost(r, comp.hostname, port)) { result.err.status = HTTP_BAD_GATEWAY; result.err.desc = "Destination URI refers to a different server."; return result; } /* we have verified that the requested URI denotes the same server as the current request. Therefore, we can use ap_sub_req_lookup_uri() */ /* reconstruct a URI as just the path */ new_file = ap_unparse_uri_components(r->pool, &comp, UNP_OMITSITEPART); /* * Lookup the URI and return the sub-request. Note that we use the * same HTTP method on the destination. This allows the destination * to apply appropriate restrictions (e.g. readonly). */ result.rnew = ap_sub_req_method_uri(r->method, new_file, r, NULL); return result;}/* ---------------------------------------------------------------**** XML UTILITY FUNCTIONS*//* validate that the root element uses a given DAV: tagname (TRUE==valid) */int dav_validate_root(const ap_xml_doc *doc, const char *tagname){ return doc->root && doc->root->ns == AP_XML_NS_DAV_ID && strcmp(doc->root->name, tagname) == 0;}/* find and return the (unique) child with a given DAV: tagname */ap_xml_elem *dav_find_child(const ap_xml_elem *elem, const char *tagname){ ap_xml_elem *child = elem->first_child; for (; child; child = child->next) if (child->ns == AP_XML_NS_DAV_ID && !strcmp(child->name, tagname)) return child; return NULL;}/* gather up all the CDATA into a single string */const char *dav_xml_get_cdata(const ap_xml_elem *elem, apr_pool_t *pool, int strip_white){ apr_size_t len = 0; ap_text *scan; const ap_xml_elem *child; char *cdata; char *s; apr_size_t tlen; for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) len += strlen(scan->text); for (child = elem->first_child; child != NULL; child = child->next) { for (scan = child->following_cdata.first; scan != NULL; scan = scan->next) len += strlen(scan->text); } cdata = s = apr_palloc(pool, len + 1); for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) { tlen = strlen(scan->text); memcpy(s, scan->text, tlen); s += tlen; } for (child = elem->first_child; child != NULL; child = child->next) { for (scan = child->following_cdata.first; scan != NULL; scan = scan->next) { tlen = strlen(scan->text); memcpy(s, scan->text, tlen); s += tlen; } } *s = '\0'; if (strip_white && len > 0) { /* trim leading whitespace */ while (apr_isspace(*cdata)) /* assume: return false for '\0' */ ++cdata; /* trim trailing whitespace */ while (len-- > 0 && apr_isspace(cdata[len])) continue; cdata[len + 1] = '\0'; } return cdata;}/* ---------------------------------------------------------------**** Timeout header processing***//* dav_get_timeout: If the Timeout: header exists, return a time_t * when this lock is expected to expire. Otherwise, return * a time_t of DAV_TIMEOUT_INFINITE. * * It's unclear if DAV clients are required to understand * Seconds-xxx and Infinity time values. We assume that they do. * In addition, for now, that's all we understand, too. */time_t dav_get_timeout(request_rec *r){ time_t now, expires = DAV_TIMEOUT_INFINITE; const char *timeout_const = apr_table_get(r->headers_in, "Timeout"); const char *timeout = apr_pstrdup(r->pool, timeout_const), *val; if (timeout == NULL) return DAV_TIMEOUT_INFINITE; /* Use the first thing we understand, or infinity if * we don't understand anything. */ while ((val = ap_getword_white(r->pool, &timeout)) && strlen(val)) { if (!strncmp(val, "Infinite", 8)) { return DAV_TIMEOUT_INFINITE; } if (!strncmp(val, "Second-", 7)) { val += 7; /* ### We need to handle overflow better: * ### timeout will be <= 2^32 - 1 */ expires = atol(val); now = time(NULL); return now + expires; } } return DAV_TIMEOUT_INFINITE;}/* ---------------------------------------------------------------**** If Header processing***//* add_if_resource returns a new if_header, linking it to next_ih. */static dav_if_header *dav_add_if_resource(apr_pool_t *p, dav_if_header *next_ih, const char *uri, size_t uri_len){ dav_if_header *ih; if ((ih = apr_pcalloc(p, sizeof(*ih))) == NULL) return NULL; ih->uri = uri; ih->uri_len = uri_len; ih->next = next_ih; return ih;}/* add_if_state adds a condition to an if_header. */static dav_error * dav_add_if_state(apr_pool_t *p, dav_if_header *ih, const char *state_token, dav_if_state_type t, int condition, const dav_hooks_locks *locks_hooks){ dav_if_state_list *new_sl; new_sl = apr_pcalloc(p, sizeof(*new_sl)); new_sl->condition = condition;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -