⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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_method(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.
        */
        apr_sockaddr_port_get(&port, r->connection->local_addr);
        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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -