Roxen.git / server / etc / modules / PropertySet.pike

version» Context lines:

Roxen.git/server/etc/modules/PropertySet.pike:1: - //! Contains methods for querying and setting of properties for - //! a file. + //! Contains methods for querying and setting of properties for a + //! resource.   //! -  + //! This default implementation takes care of the most important RFC + //! 2518 properties for ordinary files and directories in read-only + //! mode. + //!   //! Objects of this class are usually created through   //! @[RoxenModule()->query_properties()].    - //! RequestID for the set. - RequestID id; + #ifdef DAV_DEBUG + #define DAV_WERROR(X...) werror(X) + #else /* !DAV_DEBUG */ + #define DAV_WERROR(X...) + #endif /* DAV_DEBUG */      //! Path for which these properties apply.   string path;      //! Status information about @[path] as returned by @[stat_file()].   Stat st;    -  + //! The current request. + RequestID id; +    //! Create a new property set.   //!   //! Usually called via @[query_properties()].   static void create(string path, Stat st, RequestID id)   { -  global::id = id; -  global::st = st; +     global::path = path; -  +  global::st = st; +  global::id = id;   }      //! Destruction callback.   //!   //! Note that this function must unroll any uncommitted   //! property changes.   static void destroy()   {   }    -  + //! Called by the default @[query_property] implementation to get the + //! response headers a GET or HEAD request on @[path] would yield. + //! It's used to fill in the properties that should reflect various + //! response headers. + mapping(string:string) get_response_headers(); +  + private constant all_properties_common = (< +  "DAV:getcontentlength", +  "DAV:getcontenttype", +  "DAV:displayname", +  "DAV:resourcetype", +  "DAV:supportedlock", +  "DAV:iscollection", +  "DAV:isfolder", + >); +  + private constant all_properties_file = all_properties_common + (< +  "http://apache.org/dav/props/executable", + >); +  + private constant all_properties_dir = all_properties_common; +    //! Returns a multiset with the names of all supported properties.   //!   //! @note   //! Only properties that should be listed by @tt{<DAV:allprop/>@}   //! are returned.   //!   //! @note   //! The following properties are required to keep   //! @tt{Microsoft Data Access Internet Publishing Provider DAV 1.1@}   //! as supplied with @tt{Microsoft Windows 2000@} happy: -  + //!   //! @string   //! @value "DAV:creationdate"   //! RFC2518 13.1 -  + //!   //! @value "DAV:displayname"   //! RFC2518 13.2 -  + //!   //! @value "DAV:getcontentlanguage"   //! RFC2518 13.3 -  + //!   //! @value "DAV:getcontentlength"   //! RFC2518 13.4 -  + //!   //! @value "DAV:getcontenttype"   //! RFC2518 13.5 -  + //! + //! @value "DAV:getetag" + //! RFC2518 13.6 + //!   //! @value "DAV:getlastmodified"   //! RFC2518 13.7 -  + //!   //! @value "DAV:resourcetype"   //! RFC2518 13.9   //! -  + //! @value "DAV:supportedlock" + //! RFC2518 13.11 + //!   //! @value "DAV:defaultdocument"   //! @tt{draft-hopmann-collection-props-00@} 1.3   //!   //! Specifies the default document for a collection.   //!   //! This property contains an URL that identifies the default   //! document for a collection. This is intended for collection   //! owners to be able to set a default document, for example   //! @tt{index.html@} or @tt{default.html@}. If this property   //! is absent, other means must be found to determine the default   //! document.   //!   //! If this property is present, but null, the collection does   //! not have a default document and the collection member listing   //! should be used (or nothing).   //!   //! Note: The server implementation does not need to store this   //! property in the normal property store (the property could well   //! be live). -  + //!   //! @value "DAV:ishidden" - //! @tt{draft-hopmann-collection-props-00@} 1.7 + //! @tt{draft-hopmann-collection-props-00@} 1.6   //!   //! Specifies whether or not a resource is hidden.   //!   //! This property identifies whether or not a resource is hidden.   //! It contains either the values @tt{"1"@} or @tt{"0"@}. This   //! can be considered a hint to the client UI: under normal   //! conditions, for non-expert users, hidden files should not be   //! exposed to users. The server may omit the hidden resource from   //! some presentational listings, otherwise the client is responsible   //! for removing hidden resources when displaying to the user. If   //! this property is absent, the collection is not hidden. Since this   //! property provides no actual form of protection to the resources,   //! this MUST NOT be used as a form of access control and should   //! only be used for presentation purposes. -  + //!   //! @value "DAV:isstructureddocument"   //! @tt{draft-hopmann-collection-props-00@} 1.7   //!   //! Specifies whether the resource is a structured document.   //!   //! A structured document is a collection (@tt{DAV:iscollection@}   //! should also be true), so @tt{COPY@}, @tt{MOVE@} and @tt{DELETE@}   //! work as for a collection. The structured document may behave at   //! times like a document. For example, clients may wish to display   //! the resource as a document rather than as a collection. This
Roxen.git/server/etc/modules/PropertySet.pike:134:   //! structure queries, which would suffice for this and for many more   //! powerful queries, but seems inappropriate to standardize at this   //! time.   //!   //! @value "DAV:isreadonly"   //! Microsoft specific.   //!   //! The @tt{isreadonly@} field specifies whether an item can be   //! modified or deleted. If this field is TRUE, the item cannot   //! be modified or deleted. + //!   //! @value "DAV:isroot"   //! Microsoft specific.   //!   //! The @tt{DAV:isroot@} field specifies whether an item is a   //! root folder. -  + //!   //! @value "DAV:lastaccessed"   //! Microsoft specific.   //!   //! The @tt{DAV:lastaccessed@} field specifies the date and time   //! when an item was last accessed. This field is read-only. -  + //!   //! @value "DAV:href"   //! Microsoft specific.   //!   //! Read-only. The @b{absolute URL@} of an item. -  + //!   //! @value "DAV:contentclass"   //! Microsoft specific.   //!   //! The item's content class. -  + //!   //! @value "DAV:parentname"   //! Microsoft specific.   //!   //! The @tt{DAV:parentname@} field specifies the name of the folder   //! that contains an item. -  + //!   //! @value "DAV:name"   //! Microsoft specific.   //!   //! Unknown definition.   //! @endstring -  + //! + //! Also, the MS DAV client requires a type argument to be able to + //! parse date/time fields correctly, even when they are formatted + //! according to the standard. @[XMLPropStatNode.add_property] has + //! special cases for this for @tt{DAV:creationdate@} and + //! @tt{DAV:getlastmodified@}.   multiset(string) query_all_properties()   { -  multiset(string) res = (< -  "DAV:creationdate", // RFC2518 13.1 -  "DAV:displayname", // RFC2518 13.2 -  //"DAV:getcontentlanguage", // RFC2518 13.3 -  "DAV:getcontentlength", // RFC2518 13.4 -  "DAV:getcontenttype", // RFC2518 13.5 -  "DAV:getetag", // RFC2518 13.6 -  "DAV:getlastmodified", // RFC2518 13.7 -  "DAV:resourcetype", // RFC2518 13.9 -  "DAV:supportedlock", // RFC2518 13.11 +  multiset(string) props = +  (st->isreg ? all_properties_file : all_properties_dir) + (<>);    -  "DAV:iscollection", // draft-ietf-dasl-protocol-00 5.18 +  // This isn't necessary for the Content-Length and Content-Type +  // headers since RequestID.make_response_headers always sets those. +  mapping(string:string) hdrs = get_response_headers(); +  if (hdrs["Content-Language"]) props["DAV:getcontentlanguage"] = 1; +  if (hdrs->ETag) props["DAV:getetag"] = 1; +  if (hdrs["Last-Modified"]) props["DAV:getlastmodified"] = 1;    -  "DAV:ishidden", // draft-hopmann-collection-props-00 1.6 -  -  //"DAV:isreadonly", // MS uses this. -  //"DAV:lastaccessed", // MS uses this. -  //"DAV:href", // MS uses this. -  //"DAV:contentclass", // MS uses this. -  //"DAV:parentname", // MS uses this. -  //"DAV:name", // MS uses this. -  >); -  if (st->isreg) { -  res += (< -  "http://apache.org/dav/props/executable", -  >); -  } else if (st->isdir) { -  res += (< -  //"DAV:defaultdocument", // draft-hopmann-collection-props-00 1.3 -  //"DAV:isstructureddocument", // draft-hopmann-collection-props-00 1.7 -  //"DAV:isroot", // MS uses this. -  >); +  return props;   } -  return res; - } +       //! Returns the value of the specified property, or an error code   //! mapping.   //!   //! The default implementation takes care of the most important RFC   //! 2518 properties.   //!   //! @note   //! Returning a string is shorthand for returning an array   //! with a single text node.   string|array(Parser.XML.Tree.Node)|mapping(string:mixed)    query_property(string prop_name)   {    switch(prop_name) { -  + #if 0 +  // We don't really have any idea of the creation time in a unix +  // style file system.    case "DAV:creationdate": // RFC2518 13.1    int t = st->ctime;    if (t > st->atime) t = st->atime;    if (t > st->mtime) t = st->mtime;    return Roxen.iso8601_date_time(t); // MS kludge. -  + #endif +     case "DAV:displayname": // RFC2518 13.2    if ((path == "") || (path == "/")) return "/";    if (path[-1] == '/') return basename(path[..sizeof(path)-2]);    return basename(path); -  +     case "DAV:getcontentlanguage":// RFC2518 13.3 -  return "en"; // MS kludge. +  return get_response_headers()["Content-Language"]; +     case "DAV:getcontentlength": // RFC2518 13.4 -  if (st->isreg) { -  return (string)st->size; -  } -  return "0"; +  return get_response_headers()["Content-Length"]; +     case "DAV:getcontenttype": // RFC2518 13.5 -  if (st->isreg) { -  return id->conf-> -  type_from_filename(path, 0, -  lower_case(Roxen.extension(path, id))); -  } -  return "application/octet-stream"; +  return get_response_headers()["Content-Type"]; +     case "DAV:getetag": // RFC2518 13.6 -  return "FOOBAR"; +  return get_response_headers()->ETag; +     case "DAV:getlastmodified": // RFC2518 13.7 -  return Roxen.http_date(st->mtime); +  return get_response_headers()["Last-Modified"]; +     case "DAV:resourcetype": // RFC2518 13.9    if (st->isdir) {    return ({    Parser.XML.Tree.ElementNode("DAV:collection", ([])), // 12.2    });    }    return 0; -  +     case "DAV:supportedlock": // RFC2518 13.11    return ""; -  +     case "http://apache.org/dav/props/executable":    // http://www.webdav.org/mod_dav/:    //    // Name: executable    // Namespace: http://apache.org/dav/props/    // Purpose: Describes the executable status of the resource.    // Value: "T" | "F" (case is significant)    // Description: This property is defined by mod_dav's default    // repository, the "filesystem" repository. It    // corresponds to the "executable" permission flag    // in most filesystems.    //    // This property is not defined on collections.    if (st->isreg) {    if (st->mode & 0111) return "T";    return "F";    }    break;    -  case "DAV:isreadonly": // draft-ietf-dasl-protocol-00 -  if (!(st->mode & 0222)) { -  return "1"; -  } + #if 0 +  // Need more interaction with directory listing modules to handle +  // this. +  case "DAV:defaultdocument": // draft-hopmann-collection-props-00 1.3 +  return ""; +  +  // Absence means not hidden. +  case "DAV:ishidden": // draft-hopmann-collection-props-00 1.6    return "0"; -  +  +  // Absence means not a structured document. +  case "DAV:isstructureddocument": // draft-hopmann-collection-props-00 1.7 +  return "0"; + #endif +     case "DAV:iscollection": // draft-ietf-dasl-protocol-00 5.18    case "DAV:isfolder": // draft-hopmann-collection-props-00 1.5    if (st->isdir) {    return "1";    }    return "0"; -  case "DAV:ishidden": // draft-hopmann-collection-props-00 1.6 -  return "0"; +    #if 0    // The following are properties in the DAV namespace    // that Microsoft has stolen. -  +  case "DAV:isreadonly": // MS +  if (!(st->mode & 0222)) { +  return "1"; +  } +  return "0";    case "DAV:isroot": // MS -  if (path == "/") return "1"; +  if (path == "") return "1";    return "0"; -  case "DAV:isstructureddocument"://MS -  return "0"; +     case "DAV:lastaccessed": // MS    return Roxen.iso8601_date_time(st->atime);    case "DAV:href": // MS    return sprintf("%s://%s%s%s%s",    id->port_obj->prot_name,    id->misc->host || id->port_obj->ip ||    gethostname(),    (id->port_obj->port == id->port_obj->port)?    "":(":"+(string)id->port_obj->port),    id->port_obj->path||"",    combine_path(query_location(), path)); -  case "DAV:name": // MS -  return combine_path(query_location(), path); +     case "DAV:contentclass": // MS    return "";    case "DAV:parentname": // MS    return ""; -  case "DAV:defaultdocument": // MS -  return ""; +  case "DAV:name": // MS +  return combine_path(query_location(), path);   #endif /* 0 */ -  +     default:    break;    } - #ifdef DAV_DEBUG -  report_debug("query_property(): Unimplemented property:%O\n", prop_name); - #endif /* DAV_DEBUG */ +  +  DAV_WERROR("query_property(): Unimplemented property:%O\n", prop_name);    // RFC 2518 8.1:    // A request to retrieve the value of a property which does not    // exist is an error and MUST be noted, if the response uses a    // multistatus XML element, with a response XML element which    // contains a 404 (Not Found) status value.    return Roxen.http_status (Protocols.HTTP.HTTP_NOT_FOUND,    "No such property.");   }      // RFC 2518 8.2
Roxen.git/server/etc/modules/PropertySet.pike:485:   //! @string mode   //! @value "DAV:propname"   //! Query names of supported properties.   //! @value "DAV:allprop"   //! Query all properties and their values.   //! @value "DAV:prop"   //! Query properties specified by @[filt] and their values.   //! @endstring   //! @param result   //! Result object. - //! @param id - //! Id of the current request. +    //! @param filt   //! Optional multiset of requested properties. If this parameter   //! is @expr{0@} (zero) then all available properties are requested. - //! @param st - //! If set, this should be the stat that corresponds to @[path]. Its - //! only purpose is to save a call to @[stat_file] when the stat - //! already has been retrieved. - //! - //! @note - //! id->not_query() does not necessarily contain the same value as @[path]. +    mapping(string:mixed) find_properties(string mode,    MultiStatus result,    multiset(string)|void filt)   {    switch(mode) {    case "DAV:propname": -  foreach(indices(query_all_properties()), string prop_name) { +  foreach(query_all_properties(); string prop_name;) {    result->add_property(path, prop_name, "");    }    return 0;    case "DAV:allprop":    if (filt) {    // Used in http://sapportals.com/xmlns/cm/webdavinclude case.    // (draft-reschke-webdav-allprop-include-04).    filt |= query_all_properties();    } else {    filt = query_all_properties();
Roxen.git/server/etc/modules/PropertySet.pike:526:    case "DAV:prop":    foreach(indices(filt), string prop_name) {    result->add_property(path, prop_name,    query_property(prop_name));    }    return 0;    }    // FIXME: Unsupported DAV operation.    return 0;   } -  +