Branch: Tag:

2003-06-02

2003-06-02 12:10:29 by Henrik Grubbström (Grubba) <grubba@grubba.org>

Fixed type for type_from_filename(). Added support for some RFC 2518 requests.

Rev: server/base_server/configuration.pike:1.532

5:   // @appears Configuration   //! A site's main configuration    - constant cvs_version = "$Id: configuration.pike,v 1.531 2003/01/21 13:08:14 mast Exp $"; + constant cvs_version = "$Id: configuration.pike,v 1.532 2003/06/02 12:10:29 grubba Exp $";   #include <module.h>   #include <module_constants.h>   #include <roxen.h>
484:    }   }    - string type_from_filename( string file, int|void to, string|void myext ) + string|array(string) type_from_filename( string file, int|void to, +  string|void myext )   {    array(string)|string tmp;    if(!types_fun)
1708:    return fid;   }    + //! Implements PROPPATCH <DAV:set/>. + class PatchPropertySetCmd + { +  string property_name; +  static string|array(Parser.XML.Tree.Node) value; +  static void create(Parser.XML.Tree.Node prop_node) +  { +  property_name = prop_node->get_full_name(); +  value = prop_node->get_children(); +  +  if ((sizeof(value) == 1) && +  (value[0]->get_node_type() == Parser.XML.Tree.XML_TEXT)) { +  // Special case for a single text node. +  value = value[0]->get_text(); +  } +  } +  +  mapping(string:mixed) execute(string path, RoxenModule module, RequestID id) +  { +  return module->set_property(path, property_name, value, id); +  } + } +  + //! Implements PROPPATCH <DAV:remove/>. + class PatchPropertyRemoveCmd + { +  string property_name; +  static void create(string prop_name) +  { +  property_name = prop_name; +  } +  +  mapping(string:mixed) execute(string path, RoxenModule module, RequestID id) +  { +  return module->remove_property(path, property_name, id); +  } + } +  + //! Handle WEBDAV requests. + mapping|int(-1..0) handle_webdav(RequestID id) + { +  Parser.XML.Tree.Node xml_data; +  TRACE_ENTER("Handle WEBDAV request...", 0); +  if (catch { xml_data = id->get_xml_data(); }) { +  // RFC 2518 8: +  // If a server receives ill-formed XML in a request it MUST reject +  // the entire request with a 400 (Bad Request). +  TRACE_LEAVE("Malformed XML."); +  return Roxen.http_low_answer(400, "Malformed XML data."); +  } +  if (!(<"PROPFIND", "PROPPATCH">)[id->method]) { +  TRACE_LEAVE("Not implemented."); +  return Roxen.http_low_answer(501, "Not implemented."); +  } +  int depth = ([ "0":0, "1":1, "infinity":0x7fffffff, 0:0x7fffffff ]) +  [String.trim_whites(id->request_headers->depth)]; +  if (zero_type(depth)) { +  TRACE_LEAVE(sprintf("Bad depth header: %O.", +  id->request_headers->depth)); +  return Roxen.http_low_answer(400, "Unsupported depth."); +  } +  +  // Function to call for matching location modules. +  // +  // Arguments: +  // string path +  // int d +  // RoxenModule module +  // RequestID id +  // mixed ... extras +  function(string,int,RoxenModule,MultiStatus,RequestID,mixed ...:void) +  recur_func; +  array(mixed) extras = ({}); +  +  switch(id->method) { +  case "PROPFIND": // Get meta data. +  Parser.XML.Tree.Node propfind = +  xml_data->get_first_element("DAV:propfind", 1); +  if (!propfind) { +  return Roxen.http_low_answer(400, "Missing DAV:propfind."); +  } +  /* Valid children of <DAV:propfind> are +  * <DAV:propname /> +  * or +  * <DAV:allprop /> +  * or +  * <DAV:prop>{propertylist}*</DAV:prop> +  */ +  foreach(propfind->get_children(), Parser.XML.Tree.Node prop) { +  switch(prop->get_full_name()) { +  case "DAV:propname": +  if (recur_func) +  return Roxen.http_low_answer(400, "Bad DAV request (23.3.2.1)."); +  recur_func = lambda(string path, int d, RoxenModule module, +  MultiStatus stat, RequestID id) { +  module->recurse_find_properties(path, "DAV:propname", d, +  stat, id); +  }; +  break; +  case "DAV:allprop": +  if (recur_func) +  return Roxen.http_low_answer(400, "Bad DAV request (23.3.2.1)."); +  recur_func = lambda(string path, int d, RoxenModule module, +  MultiStatus stat, RequestID id) { +  module->recurse_find_properties(path, "DAV:allprop", d, +  stat, id); +  }; +  break; +  case "DAV:prop": +  if (recur_func) +  return Roxen.http_low_answer(400, "Bad DAV request (23.3.2.1)."); +  recur_func = lambda(string path, int d, RoxenModule module, +  MultiStatus stat, RequestID id, +  multiset(string) filt) { +  module->recurse_find_properties(path, "DAV:prop", d, +  stat, id, filt); +  }; +  extras = ({ (multiset)(prop->get_children()->get_full_name()) }); +  break; +  default: +  break; +  } +  } +  break; +  case "PROPPATCH": // Set/delete meta data. +  Parser.XML.Tree.Node propupdate = +  xml_data->get_first_element("DAV:propertyupdate", 1); +  if (!propupdate) { +  return Roxen.http_low_answer(400, "Missing DAV:propertyupdate."); +  } +  /* Valid children of <DAV:propertyupdate> are any combinations of +  * <DAV:set><DAV:prop>{propertylist}*</DAV:prop></DAV:set> +  * and +  * <DAV:remove><DAV:prop>{propertylist}*</DAV:prop></DAV:remove> +  * +  * RFC 2518 8.2: +  * Instruction processing MUST occur in the order instructions +  * are received (i.e., from top to bottom). +  */ +  array(PatchPropertyCommand) instructions = ({}); +  foreach(propupdate->get_children(), Parser.XML.Tree.Node cmd) { +  switch(cmd->get_full_name()) { +  case "DAV:set": +  case "DAV:remove": +  Parser.XML.Tree.Node prop = +  cmd->get_first_element("DAV:prop", 1); +  if (!prop) { +  TRACE_LEAVE("Bad DAV request."); +  return Roxen.http_low_answer(400, "Bad DAV request (no properties specified)."); +  } +  if (cmd->get_full_name() == "DAV:set") { +  instructions += map(prop->get_children(), PatchPropertySetCmd); +  } else { +  instructions += map(prop->get_children()->get_full_name(), +  PatchPropertyRemoveCmd); +  } +  break; +  default: +  // FIXME: Should we complain here? +  break; +  } +  } +  if (!sizeof(instructions)) { +  TRACE_LEAVE("Bad DAV request."); +  return Roxen.http_low_answer(400, "Bad DAV request (23.3.2.2)."); +  } +  recur_func = lambda(string path, int d, RoxenModule module, +  MultiStatus stat, RequestID id, +  array(PatchPropertyCommand) instructions) { +  module->recurse_patch_properties(path, d, instructions, +  stat, id); +  }; +  extras = ({ instructions }); +  break; +  default: +  break; +  } +  if (!recur_func) { +  TRACE_LEAVE("Bad DAV request."); +  return Roxen.http_low_answer(400, "Bad DAV request (23.3.2.2)."); +  } +  // FIXME: Security, DoS, etc... +  MultiStatus result = MultiStatus(); +  string href = id->not_query; +  string href_prefix = combine_path(href, "./"); +  foreach(location_modules(), [string loc, function fun]) { +  int d = depth; +  string path; +  TRACE_ENTER(sprintf("Trying module mounted at %O...", loc), +  function_object(fun)); +  if (has_prefix(href, loc)) { +  // href = loc + path. +  path = href[sizeof(loc)..]; +  } else if (d && has_prefix(loc, href_prefix) && +  ((d -= sizeof(loc[sizeof(href_prefix)..]/"/")) >= 0)) { +  // loc = href_path + ... +  // && recursion. +  path = ""; +  } else { +  TRACE_LEAVE("Miss"); +  continue; +  } + #ifdef MODULE_LEVEL_SECURITY +  if(check_security(fun, id)) { +  TRACE_LEAVE("Not allowed."); +  continue; +  } + #endif +  RoxenModule c = function_object(fun); +  TRACE_ENTER("Performing the work...", c); +  recur_func(path, d, c, result->prefix(loc), id, @extras); +  TRACE_LEAVE("Done."); +  TRACE_LEAVE("Done."); +  } +  TRACE_LEAVE("DAV request done."); +  return result->http_answer(); + } +    mixed handle_request( RequestID id )   {    function funp;
1758:    if(sub_req_limit && root_id->misc->_request_depth > sub_req_limit)    error("Subrequest limit reached. (Possibly an insertion loop.)");    +  if ((< "PROPFIND", "PROPPATCH" >)[id->method] +  /* && (id->request_headers->depth != "0") */) { +  // These need to be special cased, since they are recursive. +  return handle_webdav(id); +  } +     mapping|int res;    mapping res2;    function tmp;