📄 util.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//*** 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_new_error_tag(apr_pool_t *p, int status, int error_id, const char *desc, const char *namespace, const char *tagname){ dav_error *err = dav_new_error(p, status, error_id, desc); err->tagname = tagname; err->namespace = namespace; 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){ apr_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){ apr_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_DECLARE(dav_lookup_result) dav_lookup_uri(const char *uri, request_rec * r, int must_be_absolute){ dav_lookup_result result = { 0 }; const char *scheme; apr_port_t port; apr_uri_t comp; char *new_file; const char *domain; /* first thing to do is parse the URI into various components */ if (apr_uri_parse(r->pool, uri, &comp) != APR_SUCCESS) { 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 && must_be_absolute) { result.err.status = HTTP_BAD_REQUEST; result.err.desc = "Destination URI must be an absolute URI."; return result; } /* the URI must not have a query (args) or a fragment */ 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; } /* If the scheme or port was provided, then make sure that it matches the scheme/port of this request. If the request must be absolute, then require the (explicit/implicit) scheme/port be matching. ### hmm. if a port wasn't provided (does the parse return port==0?), ### but we're on a non-standard port, then we won't detect that the ### URI's port implies the wrong one. */ if (comp.scheme != NULL || comp.port != 0 || must_be_absolute) { /* ### not sure this works if the current request came in via https: */ scheme = r->parsed_uri.scheme; if (scheme == NULL) scheme = ap_http_scheme(r); /* insert a port if the URI did not contain one */ if (comp.port == 0) comp.port = apr_uri_port_of_scheme(comp.scheme); /* now, verify that the URI uses the same scheme as the current. request. the port must match our port. */ port = r->connection->local_addr->port; if (strcasecmp(comp.scheme, scheme) != 0#ifdef APACHE_PORT_HANDLING_IS_BUSTED || comp.port != port#endif ) { 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; } } /* 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 (comp.hostname != NULL && 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 */#ifdef APACHE_PORT_HANDLING_IS_BUSTED 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; }#endif /* 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 = apr_uri_unparse(r->pool, &comp, APR_URI_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) */DAV_DECLARE(int) dav_validate_root(const apr_xml_doc *doc, const char *tagname){ return doc->root && doc->root->ns == APR_XML_NS_DAV_ID && strcmp(doc->root->name, tagname) == 0;}/* find and return the (unique) child with a given DAV: tagname */DAV_DECLARE(apr_xml_elem *) dav_find_child(const apr_xml_elem *elem, const char *tagname){ apr_xml_elem *child = elem->first_child; for (; child; child = child->next) if (child->ns == APR_XML_NS_DAV_ID && !strcmp(child->name, tagname)) return child; return NULL;}/* gather up all the CDATA into a single string */DAV_DECLARE(const char *) dav_xml_get_cdata(const apr_xml_elem *elem, apr_pool_t *pool, int strip_white){ apr_size_t len = 0; apr_text *scan; const apr_xml_elem *child; char *cdata; char *s; apr_size_t tlen; const char *found_text = NULL; /* initialize to avoid gcc warning */ int found_count = 0; for (scan = elem->first_cdata.first; scan != NULL; scan = scan->next) { found_text = scan->text; ++found_count; len += strlen(found_text); } for (child = elem->first_child; child != NULL; child = child->next) { for (scan = child->following_cdata.first; scan != NULL; scan = scan->next) { found_text = scan->text; ++found_count; len += strlen(found_text); } } /* some fast-path cases: * 1) zero-length cdata * 2) a single piece of cdata with no whitespace to strip */ if (len == 0) return ""; if (found_count == 1) { if (!strip_white || (!apr_isspace(*found_text) && !apr_isspace(found_text[len - 1]))) return found_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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -