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.200 2004/05/12 16:12:24 mast Exp $ + // $Id: module.pike,v 1.201 2004/05/12 19:56:46 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:269:   //! for the given path. This is used for recursive operations that can   //! yield different results for different encountered files or   //! directories.   //!   //! The status is stored in the @[MultiStatus] object returned by   //! @[id->get_multi_status]. The server will use it to make a 207   //! Multi-Status response iff the module returns an empty mapping as   //! response.   //!   //! @param path - //! Path below the filesystem location to which the status applies. + //! Path (below the filesystem location) to which the status applies.   //!   //! @param status_code   //! The HTTP status code.   //!   //! @param message   //! If given, it's a message to include in the response. The   //! message may contain line feeds ('\n') and ISO-8859-1   //! characters in the ranges 32..126 and 128..255. Line feeds are   //! converted to spaces if the response format doesn't allow them.   //!
Roxen.git/server/base_server/module.pike:518:    int any_failed;    foreach(results, mapping(string:mixed) answer) {    if (any_failed = (answer && (answer->error >= 300))) {    break;    }    }    if (any_failed) {    // Unroll and fail any succeeded items.    int i;    mapping(string:mixed) answer = -  Roxen.http_status (Protocols.HTTP.DAV_FAILED_DEP, "Failed dependency."); +  Roxen.http_status (Protocols.HTTP.DAV_FAILED_DEP);    for(i = 0; i < sizeof(results); i++) {    if (!results[i] || results[i]->error < 300) {    result->add_property("", instructions[i]->property_name,    answer);    } else {    result->add_property("", instructions[i]->property_name,    results[i]);    }    }    properties->unroll();
Roxen.git/server/base_server/module.pike:890:   //! there is no other lock already that conflicts with this one, i.e.   //! that @code{check_locks(path,lock->recursive,id)@} would return   //! @expr{LOCK_NONE@} if @expr{lock->lockscope@} is   //! @expr{"DAV:exclusive"@}, or @expr{< LOCK_OWN_BELOW@} if   //! @expr{lock->lockscope@} is @expr{"DAV:shared"@}.   //!   //! This function is only provided as a helper to call from   //! @[lock_file] if the default lock implementation is to be used.   //!   //! @param path - //! Normalized path below the filesystem location that the lock + //! Normalized path (below the filesystem location) that the lock   //! applies to.   //!   //! @param lock   //! The lock to register.   //!   //! @note   //! The default implementation only handles the @expr{"DAV:write"@}   //! lock type. It uses @[resource_id] to map paths to unique resources   //! and @[authenticated_user_id] to tell users apart.   static void register_lock(string path, DAVLock lock, RequestID id)
Roxen.git/server/base_server/module.pike:948:   //! obtaining an exclusive lock. A resource that doesn't exist can be   //! locked, provided the directory it would be in exists (relaxed in   //! RFC 2518Bis (working draft)).   //!   //! It's up to @[find_file] et al to actually check that the necessary   //! locks are held. It can preferably use @[write_access] for that,   //! which has a default implementation for checking   //! @expr{"DAV:write"@} locks.   //!   //! @param path - //! Normalized path below the filesystem location that the lock + //! Normalized path (below the filesystem location) that the lock   //! applies to.   //!   //! @param lock   //! The lock to register.   //!   //! @returns   //! Returns @expr{0@} if the lock is successfully installed or if   //! locking isn't used. Returns a status mapping if an error   //! occurred.   mapping(string:mixed) lock_file(string path,    DAVLock lock,    RequestID id)   {    return 0;   }      //! Remove @[lock] that currently is locking the resource at @[path].   //!   //! @param path - //! Normalized path below the filesystem location that the lock + //! Normalized path (below the filesystem location) that the lock   //! applies to.   //!   //! @param lock   //! The lock to unregister. (It must not be changed or destructed.)   //!   //! @returns   //! Returns a status mapping on any error, zero otherwise.   mapping(string:mixed) unlock_file (string path,    DAVLock lock,    RequestID id)
Roxen.git/server/base_server/module.pike:1005:    ASSERT_IF_DEBUG (lock /*%O*/ == removed_lock /*%O*/, lock, removed_lock);    TRACE_LEAVE("Ok.");    return 0;   }      //! Checks that the conditions specified by the WebDAV @expr{"If"@}   //! header are fulfilled on the given path (RFC 2518 9.4). This means   //! that locks are checked as necessary using @[check_locks].   //!   //! @param path - //! Path below the filesystem location that the lock applies to. + //! Path (below the filesystem location) that the lock applies to.   //!   //! @param recursive   //! If @expr{1@} also check write access recursively under @[path].   //!   //! @returns   //! Returns @expr{0@} (zero) on success, a status mapping on   //! failure, or @expr{1@} if @[recursive] is set and write access is   //! allowed on this level but maybe not somewhere below. The caller   //! should in the last case do the operation on this level if   //! possible and then handle each member in the directory
Roxen.git/server/base_server/module.pike:1148:   {    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].   //!   //! It's unspecified if it works recursively or not, but if it does - //! then it has to check DAV locks through @[write_access] - //! recursively. + //! 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.   //!   //! @note   //! The default implementation falls back to @[find_file()].   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) || -  Roxen.http_status(tmp_id->misc->error_code || 404); +  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. + //! 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()].   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:1200:       if (st->isdir) {    // RFC 2518 8.6.2    // The DELETE operation on a collection MUST act as if a    // "Depth: infinity" header was used on it.    int fail;    if (!has_suffix(path, "/")) path += "/";    foreach(find_dir(path, id) || ({}), string fname) {    fname = path + fname;    if (Stat sub_stat = stat_file (fname, id)) { -  SIMPLE_TRACE_ENTER (this, "Deleting %O recursively", fname); +  SIMPLE_TRACE_ENTER (this, "Deleting %O", fname);    if (mapping(string:mixed) sub_res = recurse(fname, sub_stat)) {    // RFC 2518 8.6.2 -  // 424 (Failed Dependancy) errors SHOULD NOT be in the -  // 207 (Multi-Status). -  // +     // Additionally 204 (No Content) errors SHOULD NOT be returned    // in the 207 (Multi-Status). The reason for this prohibition    // is that 204 (No Content) is the default success code. -  if (sub_res->error != 204 && sub_res->error != 424) { +  if (sizeof (sub_res) && sub_res->error != 204) {    stat->add_status(fname, sub_res->error, sub_res->rettext);    }    if (sub_res->error >= 300) fail = 1;    }    }    }    if (fail) {    SIMPLE_TRACE_LEAVE ("Partial failure"); -  return Roxen.http_status(424); +  return ([]);    }    }       SIMPLE_TRACE_LEAVE ("");    return delete_file (path, id);    };       return recurse(path, st) || Roxen.http_status(204);   }   
Roxen.git/server/base_server/module.pike:1348:    if (res && res->error >= 300) return res;    return copy_properties(source, destination, behavior, id) || res;   }      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 yet."); +  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,    mapping(string:PropertyBehavior) behavior,    Overwrite overwrite, RequestID id)   {    SIMPLE_TRACE_ENTER(this, "recurse_copy_files(%O, %O, %O, %O, %O)\n",    source, destination, depth, behavior, id);    string src_tmp = has_suffix(source, "/")?source:(source+"/");
Roxen.git/server/base_server/module.pike:1385:    if (!st) {    TRACE_LEAVE("Source not found.");    return 0; /* FIXME: 404? */    }    // FIXME: Check destination?    if (st->isdir) {    mapping(string:mixed) res =    copy_collection(source, destination,    behavior[loc+source] || behavior[0],    overwrite, result, id); -  if (res && (res->error != 204) && (res->error != 201)) { -  if (res->error >= 300) { +  if (res && res->error >= 300) {    // RFC 2518 8.8.3 and 8.8.8 (error minimization).    TRACE_LEAVE("Copy of collection failed.");    return res;    } -  result->add_status(destination, res->error, res->rettext); -  } +     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)) { -  result->add_status(combine_path_unix(destination, filename), -  sub_res->error, sub_res->rettext); +  result->add_status(subdst, sub_res->error, sub_res->rettext);    }    }    TRACE_LEAVE("");    return res;    } else {    TRACE_LEAVE("");    return copy_file(source, destination,    behavior[query_location()+source] ||    behavior[0],    overwrite, id);    }    };    -  return recurse (source, destination, depth); +  int start_ms_size = id->multi_status_size(); +  mapping(string:mixed) res = recurse (source, destination, depth); +  if (res && res->error != 204 && res->error != 201) +  return res; +  else if (id->multi_status_size() != start_ms_size) +  return ([]); +  else +  return res;   }      string real_file(string f, RequestID id){}      void add_api_function( string name, function f, void|array(string) types)   {    _api_functions[name] = ({ f, types });   }      mapping api_functions()