src/server/safs/pcheck.c

Fri, 17 Jan 2020 22:23:30 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 17 Jan 2020 22:23:30 +0100
branch
webdav
changeset 231
4714468b9b7e
parent 139
29ac9aed4889
permissions
-rw-r--r--

implement multistatus writer

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
 *
 * THE BSD LICENSE
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer. 
 * 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. 
 *
 * Neither the name of the  nor the names of its contributors may be
 * used to endorse or promote products derived from this software without 
 * specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER 
 * OR 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.
 */

/*
 * open web server code from safs/pcheck.cpp
 */

#include "pcheck.h"

#include "../util/pblock.h"

/* --------------------------- pcheck_find_path --------------------------- */


/*
 * Takes a given path, and figures out if there is any path_info attached.
 * If no explicit path_info was provided by nametrans, and the file doesn't 
 * exist as specified, it tries to find it by groping through the filesystem.
 * 
 * This type of implicit path_info cannot be attached to directories. Such
 * a request will be flagged as not found.
 * 
 * pb unused.
 */

static char* find_param(char *uri, char *param)
{
    // Find ;parameters on the end of uri
    if (param > uri) {
        if (*param == FILE_PATHSEP) {
            --param;
        }
        while (param > uri && *param != FILE_PATHSEP && *param != ';') {
            --param;
        }
        if (*param == ';') {
            return param;
        }
    }

    return NULL;
}

static PRBool set_path_info(Request *rq, char *uri, int path_info_depth)
{
    // Find trailing path components in uri, e.g. the "/baz;qux/quux" in
    // "/cgi-bin/foo.pl;bar/baz;qux/quux" (here path_info_depth would be 2)
    char *path_info = &uri[strlen(uri)];
    while (path_info > uri && path_info_depth) {
        --path_info;
        if (*path_info == FILE_PATHSEP) {
            --path_info_depth;
        }
    }

    if (*path_info) {
        pblock_nvinsert("path-info", path_info, rq->vars);
        return PR_TRUE;
    }

    return PR_FALSE;
}

int pcheck_find_path(pblock *pb, Session *sn, Request *rq) 
{
    char *path = pblock_findkeyval (pb_key_path, rq -> vars);
    char *path_info   = pblock_findkeyval (pb_key_path_info  , rq -> vars);
    char *script_name = pblock_findkeyval (pb_key_script_name, rq -> vars);
    //NSFCFileInfo *finfo = NULL;
    struct stat stbuf;
    struct stat *finfo = NULL;

    rq->directive_is_cacheable = 1;

    if (path_info != NULL || script_name != NULL || path == NULL)
	return REQ_NOACTION;// ruslan: bail out right away for performance (no need to go into file cache)

    if (!*path)
        return REQ_NOACTION;

    /*
    if ((INTrequest_info_path(path, rq, NULL) == PR_SUCCESS))
        return REQ_NOACTION;
    */

    rq->directive_is_cacheable = 0;

    path_info = &path[strlen(path) - 1];

    char *forward = pblock_findkeyval(pb_key_find_pathinfo_forward, rq->vars);
    char *base = NULL;
    if (forward) {
        base   = pblock_findval("ntrans-base"  , rq -> vars);
        if (!base) forward = NULL;
    }

    int path_info_depth = 0;
    
    if(!forward) {
        while (1) {
            /* Change all occurrences of '/' to FILE_PATHSEP for WIN32 */
            for(  ; path_info != path; --path_info)
                if (*path_info == FILE_PATHSEP)
                    break;
            for(  ; path_info != path; --path_info) {
                ++path_info_depth;
                if (*(path_info - 1) != FILE_PATHSEP)
                    break;
            }

            if (path_info == path)
                break;

            *path_info = '\0';
            //if ((INTrequest_info_path(path, rq, &finfo) == PR_SUCCESS) && finfo) {
            struct stat *st = request_stat_path(path, rq);
            if(st) {
                finfo = &stbuf;
                stbuf = *st;
                free(st);
            }
            if(finfo) {
                //if (finfo->pr.type != PR_FILE_FILE) {
                if(S_ISDIR(finfo->st_mode)) {
                    *path_info = FILE_PATHSEP;
                    if (set_path_info(rq, pblock_findkeyval(pb_key_uri, rq->reqpb), 0)) {
                        return REQ_PROCEED;
                    }
                    break;
                } else {
                    set_path_info(rq, pblock_findkeyval(pb_key_uri, rq->reqpb), path_info_depth);
                    return REQ_PROCEED;
                }
            } else {
                *path_info-- = FILE_PATHSEP;
            }
        }
        /* This was changed to support virtual documents */
        return REQ_NOACTION;
    } else {
        int baselen = strlen(base);
        if (strncmp(path, base, baselen))
            return REQ_NOACTION;

        path_info = &path[baselen];
        if (*path_info == '/')
            path_info++;

        while (1) {
            for(  ; *path_info; ++path_info)
                if (*path_info == FILE_PATHSEP)
                    break;

            if (!*path_info) {
                if (set_path_info(rq, pblock_findkeyval(pb_key_uri, rq->reqpb), 0)) {
                    return REQ_PROCEED;
                }
                break;
            }

            *path_info = '\0';
            //if ((INTrequest_info_path(path, rq, &finfo) == PR_SUCCESS) && finfo) {
            struct stat *st = request_stat_path(path, rq);
            if(st) {
                stbuf = *st;
                finfo = &stbuf;
                free(st);
            }
            if(finfo) {
                //if (finfo->pr.type != PR_FILE_FILE) {
                if(S_ISDIR(finfo->st_mode)) {
                    *path_info++ = FILE_PATHSEP;
                } else {
                    char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
                    *path_info = FILE_PATHSEP;
    #ifdef XP_WIN32
                    char *unmpath = pblock_findval("unmuri", rq->vars);
                    if (unmpath) {
                        char *nm = &path_info[strlen(path_info)-1];
                        char *unm = &unmpath[strlen(unmpath)-1];
                        while(nm != path_info && unm != unmpath) {
                            if (*nm != *unm) {
                                if (*unm == '\\' && *nm == '/')
                                    *nm = *unm;
                                else
                                    PR_ASSERT(0);
                            }
                            nm--;
                            unm--;
                        }
                        uri = unmpath;
                    }
    #endif
                    char *t = path_info;
                    for(; *t; ++t)
                        if (*t == FILE_PATHSEP)
                            ++path_info_depth;
                    *path_info = '\0';
                    set_path_info(rq, uri, path_info_depth);
                    return REQ_PROCEED;
                }
            }
            else {
               *path_info = FILE_PATHSEP;
                break;
            }
        }

        /* This was changed to support virtual documents */
        return REQ_NOACTION;
    }
}

mercurial