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.189 2004/05/10 11:43:07 grubba Exp $ + // $Id: module.pike,v 1.190 2004/05/10 13:41:20 grubba 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:402:    SIMPLE_TRACE_LEAVE ("");    return res;   }      //! Returns the value of the specified property, or an error code   //! mapping.   //!   //! @note   //! Returning a string is shorthand for returning an array   //! with a single text node. - string|array(Parser.XML.Tree.Node)|mapping(string:mixed) + string|array(Parser.XML.Tree.SimpleNode)|mapping(string:mixed)    query_property(string path, string prop_name, RequestID id)   {    mapping(string:mixed)|PropertySet properties = query_properties(path, id);    if (!properties) {    return Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND,    "No such file or directory.");    }    if (mappingp (properties))    return properties;    return properties->query_property(prop_name) ||
Roxen.git/server/base_server/module.pike:538:    SIMPLE_TRACE_LEAVE ("");    return 0;   }      //! Convenience variant of @[patch_properties()] that sets a single   //! property.   //!   //! @returns   //! Returns a mapping on any error, zero otherwise.   mapping(string:mixed) set_property (string path, string prop_name, -  string|array(Parser.XML.Tree.Node) value, +  string|array(Parser.XML.Tree.SimpleNode) value,    RequestID id)   {    mapping(string:mixed)|PropertySet properties = query_properties(path, id);    if (!properties) return Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND,    "File not found.");    if (mappingp (properties)) return properties;       mapping(string:mixed) result = properties->start();    if (result) return result;   
Roxen.git/server/base_server/module.pike:1162:   mapping 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, id);   }    + //! State of the Overwrite header. + static enum Overwrite { +  NEVER_OVERWRITE = -1, //! The Overwrite header is "F". +  MAYBE_OVERWRITE = 0, //! No Overwrite header. +  DO_OVERWRITE = 1, //! The Overwrite header is "T". + }; +  + //! State of the DAV:PropertyBehavior for this source. + static enum PropertyBehavior { +  PROPERTY_OMIT = -1, //! DAV:omit (Omit if it can't be copied). +  PROPERTY_COPY = 0, //! Copy if it can't be kept alive (default). +  PROPERTY_ALIVE = 1, //! DAV:keepalive (Live properties must be kept alive). + } +  + mapping 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_properties(source, id); +  PropertySet destination_properties = query_properties(destination, id); +  +  multiset(string) property_set = source_properties->query_all_properties(); +  mapping res; +  foreach(property_set; string property_name;) { +  SIMPLE_TRACE_ENTER(this, "Copying the property %O.", property_name); +  string|array(Parser.XML.Tree.SimpleNode)|mapping(string:mixed) source_val = +  source_properties->query_property(property_name); +  if (mappingp(source_val)) { +  TRACE_LEAVE("Reading of property failed. Skipped."); +  continue; +  } +  string|array(Parser.XML.Tree.SimpleNode)|mapping(string:mixed) dest_val = +  destination_properties->query_property(property_name); +  if (dest_val == source_val) { +  TRACE_LEAVE("Destination already has the correct value."); +  continue; +  } +  mapping res = +  destination_properties->set_property(property_name, source_val); +  if (behavior == PROPERTY_OMIT) { +  TRACE_LEAVE("Omit verify."); +  continue; +  } +  if ((behavior == PROPERTY_ALIVE) && (res->error < 300)) { +  // FIXME: Check that if the property was live in source, +  // it is still live in destination. +  // This is likely already so, since we're in the same module. +  } +  if ((res->error < 300) || +  (res->error == Protocols.HTTP.HTTP_CONFLICT)) { +  // Ok, or read-only property. +  TRACE_LEAVE("Copy ok or read-only property."); +  continue; +  } +  if (!res) { +  // 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; + } +    mapping copy_collection(string source, string destination, -  int(-1..1) behaviour, +  PropertyBehavior behavior, Overwrite overwrite,    MultiStatus.Prefixed result, RequestID id)   { -  SIMPLE_TRACE_ENTER(this, "copy_collection(%O, %O, %O, %O, %O).", -  source, destination, behaviour, result, 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);    if (st) {    // Destination exists. Check the overwrite header. -  if (id->request_headers->overwrite) { -  if (lower_case(id->request_headers->overwrite) == "t") { +  switch(overwrite) { +  case DO_OVERWRITE:    // RFC 2518 8.8.4    // If a resource exists at the destination, and the Overwrite    // header is "T" then prior to performing the copy the server    // MUST perform a DELETE with "Depth: infinity" on the    // destination resource.    TRACE_ENTER("Destination exists and overwrite is on.", this);    if (recurse_delete_files(destination, result, id)) {    // Failed to delete something.    TRACE_LEAVE("Deletion failed.");    TRACE_LEAVE("Copy collection failed.");    return Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED);    }    TRACE_LEAVE("Deletion ok."); -  } else { +  break; +  case NEVER_OVERWRITE:    TRACE_LEAVE("Destination already exists.");    return Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED); -  } -  } else { +  case MAYBE_OVERWRITE:    // No overwrite header.    // Be nice, and fail only if we don't already have a collection.    if (st->isdir) {    TRACE_LEAVE("Destination exists and is a directory."); -  return 0; +  return copy_properties(source, destination, behavior, id);    }    TRACE_LEAVE("Destination exists and is not a directory.");    return Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED);    }    }    // Create the new collection.    TRACE_LEAVE("Make a new collection."); -  return make_collection(destination, id); +  mapping res = make_collection(destination, id); +  if (res && res->error >= 300) return res; +  return copy_properties(source, destination, behavior, id) || res;   }    - mapping copy_file(string path, string dest, int(-1..1) behavior, RequestID id) + mapping copy_file(string path, string dest, PropertyBehavior behavior, +  Overwrite overwrite, RequestID id)   { -  SIMPLE_TRACE_ENTER(this, "copy_file(%O, %O, %O, %O)\n", -  path, dest, behavior, id); +  SIMPLE_TRACE_ENTER(this, "copy_file(%O, %O, %O, %O, %O)\n", +  path, dest, behavior, overwrite, id);    TRACE_LEAVE("Not implemented yet.");    return Roxen.http_status (Protocols.HTTP.HTTP_NOT_IMPL);   }      mapping recurse_copy_files(string source, string destination, int depth, -  mapping(string:int(-1..1)) behavior, +  mapping(string:PropertyBehavior) behavior, +  Overwrite overwrite,    MultiStatus.Prefixed result, RequestID id)   {    SIMPLE_TRACE_ENTER(this, "recurse_copy_files(%O, %O, %O, %O, %O, %O)\n",    source, destination, depth, behavior, result, id);    if ((source == destination) ||    has_prefix(source, destination) ||    has_prefix(destination, source)) {    TRACE_LEAVE("Source and destination overlap.");    return Roxen.http_status(403, "Source and destination overlap.");    }    Stat st = stat_file(source, id);    if (!st) {    TRACE_LEAVE("Source not found.");    return 0; /* FIXME: 404? */    }    // FIXME: Check destination?    if (st->isdir) {    mapping res = copy_collection(source, destination, -  behavior[query_location()+destination] || +  behavior[query_location()+source] ||    behavior[0], -  result, id); +  overwrite, result, id);    if (res && (res->error != 204) && (res->error != 201)) {    if (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) {    mapping sub_res = recurse_copy_files(combine_path(source, filename),    combine_path(destination, filename),    depth, -  behavior, result, id); +  behavior, overwrite, result, id);    if (sub_res && (sub_res->error != 204) && (sub_res->error != 201)) {    result->add_status(combine_path(destination, filename),    sub_res->error, sub_res->rettext);    }    }    TRACE_LEAVE("Recursive copy done.");    return res;    } else {    return copy_file(source, destination, -  behavior[query_location()+destination] || +  behavior[query_location()+source] ||    behavior[0], -  id); +  overwrite, id);    }   }      string real_file(string f, RequestID id){}      void add_api_function( string name, function f, void|array(string) types)   {    _api_functions[name] = ({ f, types });   }