Roxen.git / server / base_server / module.pike

version» Context lines:

Roxen.git/server/base_server/module.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2001, Roxen IS. - // $Id: module.pike,v 1.205 2004/05/13 14:03:28 grubba Exp $ + // $Id: module.pike,v 1.206 2004/05/13 15:39:18 mast Exp $      #include <module_constants.h>   #include <module.h>   #include <request_trace.h>      constant __pragma_save_parent__ = 1;      inherit "basic_defvar";   mapping(string:array(int)) error_log=([]);   
Roxen.git/server/base_server/module.pike:1145:   static mapping(string:mixed)|int(0..1) write_access(string relative_path,    int(0..1) recursive,    RequestID id)   {    return check_if_header (relative_path, recursive, id);   }      mapping(string:mixed)|int(-1..0)|Stdio.File find_file(string path,    RequestID id);    - //! Delete the file specified by @[path]. + //! Used by the default @[recurse_delete_files] implementation to + //! delete a file or an empty directory.   //! - //! It's unspecified if it works recursively or not, but if it does - //! then it has to check DAV locks recursively. - //! +    //! @returns - //! Returns a 204 status on success, 0 if the file doesn't exist, or - //! an appropriate status mapping for any other error. + //! Returns a 2xx series status mapping on success (typically 204 No + //! Content). Returns 0 if the file doesn't exist. Returns an + //! appropriate status mapping for any other error.   //!   //! @note   //! The default implementation falls back to @[find_file()]. - mapping(string:mixed) delete_file(string path, RequestID id) + static mapping(string:mixed) delete_file(string path, RequestID id)   {    // Fall back to find_file().    RequestID tmp_id = id->clone_me();    tmp_id->not_query = query_location() + path;    tmp_id->method = "DELETE";    // FIXME: Logging?    return find_file(path, tmp_id) ||    tmp_id->misc->error_code && Roxen.http_status (tmp_id->misc->error_code);   }      //! Delete @[path] recursively.   //!   //! The default implementation handles the recursion and calls   //! @[delete_file] for each file and empty directory.   //!   //! @returns - //! Returns @expr{0@} (zero) on file not found. Returns - //! @[Roxen.http_status(204)] on success. Returns other result - //! mappings on failure. That includes an empty mapping in case some - //! subparts couldn't be deleted, to signify a 207 Multi-Status - //! response using the info in @[id->get_multi_status()]. + //! Returns a 2xx series status mapping on success (typically 204 No + //! Content). Returns 0 if the file doesn't exist. Returns an + //! appropriate status mapping for any other error. That includes an + //! empty mapping in case some subparts couldn't be deleted, to + //! signify a 207 Multi-Status response using the info in + //! @[id->get_multi_status()].   mapping(string:mixed) recurse_delete_files(string path,    RequestID id,    void|MultiStatus.Prefixed stat)   {    SIMPLE_TRACE_ENTER (this, "Deleting %O recursively", path);    if (!stat)    id->get_multi_status()->prefix (id->url_base() + query_location()[1..]);       Stat st = stat_file(path, id);    if (!st) {
Roxen.git/server/base_server/module.pike:1231:    }    }       SIMPLE_TRACE_LEAVE ("");    return delete_file (path, id);    };       return recurse(path, st) || Roxen.http_status(204);   }    + //! Make a new collection (aka directory) at @[path]. + //! + //! @returns + //! Returns a 2xx series status on success (typically 201 Created). + //! Returns @expr{0@} (zero) if there's no directory to create the + //! new one in. Returns other result mappings on failure.   mapping(string:mixed) make_collection(string path, RequestID id)   {    // Fall back to find_file().    RequestID tmp_id = id->clone_me();    tmp_id->not_query = query_location() + path;    tmp_id->method = "MKCOL";    // FIXME: Logging?    return find_file(path, tmp_id);   }    -  + //! Copy all properties at @[source] to @[destination]. + //! + //! @param source + //! Source path below the filesystem location. + //! + //! @param destination + //! Destination path below the filesystem location. + //! + //! @param behavior + //! Specifies how to copy properties. See the @[PropertyBehavior] + //! type for details. + //! + //! @returns + //! @expr{0@} (zero) in success or an appropriate status mapping for + //! any error.   mapping(string:mixed) copy_properties(string source, string destination,    PropertyBehavior behavior, RequestID id)   {    SIMPLE_TRACE_ENTER(this, "copy_properties(%O, %O, %O, %O)",    source, destination, behavior, id);    PropertySet source_properties = query_property_set(source, id);    PropertySet destination_properties = query_property_set(destination, id);       multiset(string) property_set = source_properties->query_all_properties();    mapping(string:mixed) res;
Roxen.git/server/base_server/module.pike:1293:    // Copy failed, but attempt to copy the rest.    res = Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED);    }    TRACE_LEAVE("Copy failed.");    }    TRACE_LEAVE(res?"Failed.":"Ok.");    return res;   }      //! Used by the default @[recurse_copy_files] to copy a collection - //! (aka directory). + //! (aka directory) nonrecursively.   static mapping(string:mixed) copy_collection(string source,    string destination,    PropertyBehavior behavior,    Overwrite overwrite,    MultiStatus.Prefixed result,    RequestID id)   {    SIMPLE_TRACE_ENTER(this, "copy_collection(%O, %O, %O, %O, %O, %O).",    source, destination, behavior, overwrite, result, id);    Stat st = stat_file(destination, id);
Roxen.git/server/base_server/module.pike:1375:    return Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED);    }    }    // Create the new collection.    TRACE_LEAVE("Make a new collection.");    mapping(string:mixed) res = make_collection(destination, id);    if (res && res->error >= 300) return res;    return copy_properties(source, destination, behavior, id) || res;   }    - //! Used by the default @[recurse_copy_files] to copy a single file. - mapping(string:mixed) copy_file(string source, string destination, + //! Used by the default @[recurse_copy_files] to copy a single file + //! along with its properties. + //! + //! @param source + //! Source path below the filesystem location. + //! + //! @param destination + //! Destination path below the filesystem location. + //! + //! @param behavior + //! Specifies how to copy properties. See the @[PropertyBehavior] + //! type for details. + //! + //! @param overwrite + //! Specifies how to handle the situation if the destination already + //! exists. See the @[Overwrite] type for details. + //! + //! @returns + //! Returns a 2xx series status mapping on success (typically 201 + //! Created if the destination didn't exist before, or 204 No + //! Content otherwise). Returns 0 if the source doesn't exist. + //! Returns an appropriate status mapping for any other error. + static mapping(string:mixed) copy_file(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    SIMPLE_TRACE_ENTER(this, "copy_file(%O, %O, %O, %O, %O)\n",    source, destination, behavior, overwrite, id);    TRACE_LEAVE("Not implemented.");    return Roxen.http_status (Protocols.HTTP.HTTP_NOT_IMPL);   }    - mapping(string:mixed) recurse_copy_files(string source, string destination, int depth, + //! Copy a resource recursively from @[source] to @[destination]. + //! + //! @param source + //! Source path below the filesystem location. + //! + //! @param destination + //! Destination path below the filesystem location. + //! + //! @param behavior + //! Specifies how to copy properties. See the @[PropertyBehavior] + //! type for details. + //! + //! @param overwrite + //! Specifies how to handle the situation if the destination already + //! exists. See the @[Overwrite] type for details. + //! + //! @returns + //! Returns a 2xx series status mapping on success (typically 201 + //! Created if the destination didn't exist before, or 204 No + //! Content otherwise). Returns 0 if the source doesn't exist. + //! Returns an appropriate status mapping for any other error. That + //! includes an empty mapping in case there's a failure on some + //! subpart or at the destination, to signify a 207 Multi-Status + //! response using the info in @[id->get_multi_status()]. + mapping(string:mixed) recurse_copy_files(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   { -  SIMPLE_TRACE_ENTER(this, "recurse_copy_files(%O, %O, %O, %O, %O)\n", -  source, destination, depth, behavior, id); +  SIMPLE_TRACE_ENTER(this, "Recursive copy from %O to %O (%s)", +  source, destination, +  overwrite == DO_OVERWRITE ? "replace" : +  overwrite == NEVER_OVERWRITE ? "no overwrite" : +  "overlay");    string src_tmp = has_suffix(source, "/")?source:(source+"/");    string dst_tmp = has_suffix(destination, "/")?destination:(destination+"/");    if ((src_tmp == dst_tmp) ||    has_prefix(src_tmp, dst_tmp) ||    has_prefix(dst_tmp, src_tmp)) {    TRACE_LEAVE("Source and destination overlap.");    return Roxen.http_status(403, "Source and destination overlap.");    }       string loc = query_location();    MultiStatus.Prefixed result =    id->get_multi_status()->prefix (id->url_base() + loc[1..]);    -  mapping(string:mixed) recurse(string source, string destination, int depth) { +  mapping(string:mixed) recurse(string source, string destination) {    // Note: Already got an extra TRACE_ENTER level on entry here.       Stat st = stat_file(source, id);    if (!st) {    TRACE_LEAVE("Source not found."); -  return 0; /* FIXME: 404? */ +  return 0;    }    // FIXME: Check destination?    if (st->isdir) {    mapping(string:mixed) res =    copy_collection(source, destination, behavior, overwrite, result, id);    if (res && res->error >= 300) {    // RFC 2518 8.8.3 and 8.8.8 (error minimization).    TRACE_LEAVE("Copy of collection failed.");    return res;    } -  if (depth <= 0) { -  TRACE_LEAVE("Non-recursive copy of collection done."); -  return res; -  } -  depth--; +     foreach(find_dir(source, id), string filename) {    string subsrc = combine_path_unix(source, filename);    string subdst = combine_path_unix(destination, filename); -  SIMPLE_TRACE_ENTER(this, "Recursive copy from %O to %O, depth %O\n", -  subsrc, subdst, depth); -  mapping(string:mixed) sub_res = recurse(subsrc, subdst, depth); -  if (sub_res && (sub_res->error != 204) && (sub_res->error != 201)) { +  SIMPLE_TRACE_ENTER(this, "Copy from %O to %O\n", subsrc, subdst); +  mapping(string:mixed) sub_res = recurse(subsrc, subdst); +  if (sub_res && !(<0, 201, 204>)[sub_res->error]) {    result->add_status(subdst, sub_res->error, sub_res->rettext);    }    }    TRACE_LEAVE("");    return res;    } else {    TRACE_LEAVE("");    return copy_file(source, destination, behavior, overwrite, id);    }    };       int start_ms_size = id->multi_status_size(); -  mapping(string:mixed) res = recurse (source, destination, depth); +  mapping(string:mixed) res = recurse (source, destination);    if (res && res->error != 204 && res->error != 201)    return res;    else if (id->multi_status_size() != start_ms_size)    return ([]);    else    return res;   }    - //! Move/rename a single file. + //! Used by the default @[recurse_move_files] to move a file (and not + //! a directory) from @[source] to @[destination]. + //! + //! @param source + //! Source path below the filesystem location. + //! + //! @param destination + //! Destination path below the filesystem location. + //! + //! @param behavior + //! Specifies how to move properties. See the @[PropertyBehavior] + //! type for details. + //! + //! @param overwrite + //! Specifies how to handle the situation if the destination already + //! exists. See the @[Overwrite] type for details. + //! + //! @returns + //! Returns a 2xx series status mapping on success (typically 201 + //! Created if the destination didn't exist before, or 204 No + //! Content otherwise). Returns 0 if the source doesn't exist. + //! Returns an appropriate status mapping for any other error. That + //! includes an empty mapping in case there's a failure on some + //! subpart or at the destination, to signify a 207 Multi-Status + //! response using the info in @[id->get_multi_status()].   static mapping(string:mixed) move_file(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    // Fall back to find_file().    RequestID tmp_id = id->clone_me();    tmp_id->not_query = query_location() + source;    tmp_id->misc["new-uri"] = query_location() + destination;    tmp_id->request_headers->destination =    id->url_base() + query_location()[1..] + destination;
Roxen.git/server/base_server/module.pike:1478:    if (!res || res->error != 501) return res;    // Not implemented. Fall back to COPY + DELETE.    res = copy_file(source, destination, behavior, overwrite, id);    if (res && res->error >= 300) {    // Copy failed.    return res;    }    return delete_file(source, id);   }    - //! Move/rename a collection (aka directory) and all it's content. + //! Used by the default @[recurse_move_files] to move a collection + //! (aka directory) and all its content from @[source] to + //! @[destination]. + //! + //! @param source + //! Source path below the filesystem location. + //! + //! @param destination + //! Destination path below the filesystem location. + //! + //! @param behavior + //! Specifies how to move properties. See the @[PropertyBehavior] + //! type for details. + //! + //! @param overwrite + //! Specifies how to handle the situation if the destination already + //! exists. See the @[Overwrite] type for details. + //! + //! @returns + //! Returns a 2xx series status mapping on success (typically 201 + //! Created if the destination didn't exist before, or 204 No + //! Content otherwise). Returns 0 if the source doesn't exist. + //! Returns an appropriate status mapping for any other error. That + //! includes an empty mapping in case there's a failure on some + //! subpart or at the destination, to signify a 207 Multi-Status + //! response using the info in @[id->get_multi_status()]. + //! + //! @note + //! The function must be prepared to recurse to check DAV locks + //! properly.   static mapping(string:mixed) move_collection(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    // Fall back to find_file().    RequestID tmp_id = id->clone_me();    tmp_id->not_query = query_location() + source;    tmp_id->misc["new-uri"] = query_location() + destination;    tmp_id->request_headers->destination =    id->url_base() + query_location()[1..] + destination;
Roxen.git/server/base_server/module.pike:1520:    if (sub_res->error >= 300) {    // Failed to move some content.    fail = 1;    }    }    }    if (fail) return ([]);    return delete_file(source, id);   }    - //! Move/rename a file or collection (aka directory). + //! Move a resource from @[source] to @[destination]. + //! + //! @param source + //! Source path below the filesystem location. + //! + //! @param destination + //! Destination path below the filesystem location. + //! + //! @param behavior + //! Specifies how to move properties. See the @[PropertyBehavior] + //! type for details. + //! + //! @param overwrite + //! Specifies how to handle the situation if the destination already + //! exists. See the @[Overwrite] type for details. + //! + //! @returns + //! Returns a 2xx series status mapping on success (typically 201 + //! Created if the destination didn't exist before, or 204 No + //! Content otherwise). Returns 0 if the source doesn't exist. + //! Returns an appropriate status mapping for any other error. That + //! includes an empty mapping in case there's a failure on some + //! subpart or at the destination, to signify a 207 Multi-Status + //! response using the info in @[id->get_multi_status()].   mapping(string:mixed) recurse_move_files(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    Stat st = stat_file(source, id);    if (!st) return 0;       if (st->isdir) {    return move_collection(source, destination, behavior, overwrite, id);    }