Roxen.git / server / base_server / prototypes.pike

version» Context lines:

Roxen.git/server/base_server/prototypes.pike:238:    //!    //! @[RoxenModule.lock_file] may set this if it's zero, otherwise    //! it shouldn't change.       int(0..) expiry_time;    //! Absolute time when this lock expires.    //!    //! As a special case, if the value is @expr{0@} (zero), the lock    //! has infinite duration.    +  int(0..1) is_file; +  //! @expr{1@} if @[path] refers to a file. +     protected void create(string locktoken, string path, int(0..1) recursive,    string|SimpleNode lockscope, string|SimpleNode locktype,    int(0..) expiry_delta, array(SimpleNode) owner)    {    DAVLock::locktoken = locktoken;    DAVLock::path = path;    DAVLock::recursive = recursive;    DAVLock::lockscope = lockscope;    DAVLock::locktype = locktype;    DAVLock::expiry_delta = expiry_delta;
Roxen.git/server/base_server/prototypes.pike:450:    array(function) logger_modules();    array(function) last_modules();    array(function) first_modules();    array location_modules();    array(function) filter_modules();    void init_log_file();    int|mapping check_security(function|object a, RequestID id, void|int slevel);    void invalidate_cache();    void clear_memory_caches();    string examine_return_mapping(mapping m); -  multiset(DAVLock) find_locks(string path, int(-1..1) recursive, +  mapping(string:DAVLock) find_locks(string path, int(-1..1) recursive,    int(0..1) exclude_shared, RequestID id); -  DAVLock|LockFlag check_locks(string path, int(0..1) recursive, RequestID id); +  mapping(string:mixed)|int(-1..0) check_locks(string path, +  int(0..1) recursive, +  RequestID id);    mapping(string:mixed) unlock_file(string path, DAVLock lock, RequestID|int(0..0) id);    int expire_locks(RequestID id);    void refresh_lock(DAVLock lock);    mapping(string:mixed)|DAVLock lock_file(string path,    int(0..1) recursive,    string lockscope,    string locktype,    int(0..) expiry_delta,    array(Parser.XML.Tree.Node) owner,    RequestID id);
Roxen.git/server/base_server/prototypes.pike:1403:    //! to report in the access log.    //! @member mapping(string:string|array(string)) "moreheads"    //! If this exists, it contains headers to send in the response.    //! It overrides automatically calculated headers and headers    //! given in a response mapping (as returned by e.g.    //! @[RoxenModule.find_file]). Although http headers are case    //! insensitive, the header names in this mapping are not. All    //! names should follow the capitalization forms used in RFC    //! 2616 (c.f. @[Roxen.canonicalize_http_header]). See    //! @[add_response_header()] for more details. +  //! @member string "new-uri" +  //! Decoded and Unicode-NFC normalized @expr{"Destination"@}-header.    //! @member int(1..1) "no_proto_cache"    //! Flag indicating that the result should not be cached in    //! the protocol cache.    //! @member RequestID "orig"    //! Originating @[RequestID] for recursive requests.    //! @member int "port"    //! Port number from the canonicalized host header.    //!    //! Note that this may differ from the actual port number    //! (available in @[port_obj->port]) if eg the server is
Roxen.git/server/base_server/prototypes.pike:1768:    //! with no ending path component, @[not_query] will contain the    //! full path.    //!    //! @[not_query] usually begins with @expr{"/"@} but that is not    //! guaranteed since it's taken from the request line. It has    //! however been simplified so it is guaranteed to not contain any    //! @expr{"."@} or @expr{".."@} segments.    //!    //! The transport encoding has been decoded (i.e. any @expr{%XX@}    //! escapes and the charset according to @[input_charset]). +  //! It has also been Unicode-NFC normalized.       string input_charset;    //! The charset that was used to decode @[prestate], @[config],    //! @[query], @[not_query], @[rest_query], and the variable bindings    //! in @[real_variables].    //!    //! It is zero if they were not successfully charset decoded. That    //! is effectively the same as if the charset was ISO-8859-1.    //!    //! @seealso
Roxen.git/server/base_server/prototypes.pike:1944:    //! Returns @expr{0@} (zero) if there was no if header, or    //! if parsing of the if header failed.    //! Returns a mapping from resource name to condition on success.    //!    //! A condition is represented as an array of sub-conditions    //! (@tt{List@} in RFC 2518), where each sub-condition is an array    //! of tokens, and each token is an array of two elements, where    //! the first is one of the strings @expr{"not"@}, @expr{"etag"@},    //! or @expr{"key"@}, and the second is the value.    //! -  //! The resource @expr{0@} (zero) represents the default resource. +  //! There is an implicit @b{OR@} between sub-conditions +  //! (cf @rfc{4918:10.4.6@}), and an implicit @b{AND@} +  //! between the elements in a sub-condition. +  //! +  //! The default resource is mapped to @[not_query]. +  //! +  //! As @rfc{4918:10.4.1@} states that the mere fact that a state +  //! token appears in an If header means that it has been submitted, +  //! we as a convenience add all non-negated lock tokens to the +  //! @expr{0@} resource. +  //! +  //! @seealso +  //! @rfc{4918:10.4.2@}    mapping(string:array(array(array(string)))) get_if_data()    {    if (if_data) {    IF_HDR_MSG ("get_if_data(): Returning cached result\n");    return sizeof(if_data) && if_data;    }       if_data = ([]); // Negative caching.       string raw_header;
Roxen.git/server/base_server/prototypes.pike:1972: Inside #if 0
     #if 0    IF_HDR_MSG("get_if_data(): decoded_if: %O\n", decoded_if);   #endif       if (!sizeof(decoded_if)) {    IF_HDR_MSG("Got only whitespace.\n");    return 0;    }    -  mapping(string:array(array(array(string)))) res = ([ 0: ({}) ]); +  mapping(string:array(array(array(string)))) res = ([ +  0:({}), +  ]);    -  +  array(string) keys = ({});    string tmp_resource; -  string resource; +  string resource = not_query;    foreach(decoded_if, array(string|int|array(array(string))) symbol) {    switch (symbol[0]) {    case "special":    switch(symbol[1]) {    case '<': tmp_resource = ""; break;    case '>':    resource = tmp_resource;    tmp_resource = 0;    // Normalize.    // FIXME: Check that the protocol and server parts refer    // to this server. -  +  // NB: Above invalid according to rfc 4918 8.3. +  // +  // NB: RFC 4918 8.3 adds support for path-absolute resources. +  // NB: The resource reference may have a query section. +  //    // FIXME: Support for servers mounted on subpaths.    catch { resource = Standards.URI(resource)->path; }; -  if (!sizeof(resource) || (resource[-1] != '/')) resource += "/"; +  catch { resource = Protocols.HTTP.percent_decode(resource); }; +  catch { resource = utf8_to_string(resource); }; +  resource = Unicode.normalize(resource, "NFC"); +  if (!sizeof(resource)) resource = "/";    if (!res[resource])    res[resource] = ({});    break;    default:    if (tmp_resource) tmp_resource += sprintf("%c", symbol[1]);    break;    }    break;    case "word":    case "domain-literal":
Roxen.git/server/base_server/prototypes.pike:2026:    for (i = 0; i < sizeof(sub_expr); i++) {    switch(sub_expr[i][0]) {    case "special":    switch(sub_expr[i][1]) {    case '<': tmp_key = ""; break;    case '>':    if (!tmp_key) {    IF_HDR_MSG("No tmp_key.\n");    return 0;    } +  if (!sizeof(expr) || (expr[-1][0] != "not")) { +  keys += ({ tmp_key }); +  }    expr += ({ ({ "key", tmp_key }) });    tmp_key = 0;    break;    default:    if (tmp_key) tmp_key += sprintf("%c", sub_expr[i][1]);    break;    }    break;    case "domain-literal":    if (tmp_key) {
Roxen.git/server/base_server/prototypes.pike:2053:    expr += ({ ({ "etag", etag }) });    break;    case "word":    // State-token or Not.    if (tmp_key) {    tmp_key += sub_expr[i][1];    break;    }    if (lower_case(sub_expr[i][1]) == "not") {    // Not +  if (sizeof(expr) && (expr[-1][0] == "not")) { +  IF_HDR_MSG("Double negation."); +  report_debug("Syntax error in if-header: %O\n", raw_header); +  return 0; +  }    expr += ({ ({ "not", 0 }) });    break;    }    IF_HDR_MSG("Word outside key: %O\n", sub_expr[i][1]);    report_debug("Syntax error in if-header: %O\n", raw_header);    return 0;    }    }    if (tmp_key) {    IF_HDR_MSG("Active tmp_key: %O\n", tmp_key);    report_debug("Syntax error in if-header: %O\n", raw_header);    return 0;    }    res[resource] += ({ expr });    break;    default:    report_debug("Syntax error in if-header: %O\n", raw_header);    return 0;    }    } -  +  if (sizeof(keys)) { +  res[0] = ({ +  map(keys, lambda(string key) { +  return ({ "key", key }); +  }), +  }); +  }    if (tmp_resource) {    IF_HDR_MSG("Active tmp_resource: %O\n", tmp_resource);    report_debug("Syntax error in if-header: %O\n", raw_header);    return 0;    }    IF_HDR_MSG("get_if_data(): Parsed if header: %s:\n"    "%O\n", raw_header, res);    return if_data = res;    }   
Roxen.git/server/base_server/prototypes.pike:2872:    //!    //! @seealso    //! @[Roxen.http_status]    {    if (sizeof (args)) message = sprintf (message, @args);    ASSERT_IF_DEBUG (has_prefix (path, "/"));    get_multi_status()->add_status (url_base() + path[1..],    status_code, message);    }    +  variant void set_status_for_path (string path, mapping(string:mixed) ret) +  //! Register a status to be included in the response that applies +  //! only 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 +  //! @[get_multi_status]. +  //! +  //! @param path +  //! Absolute path in the configuration to which the status +  //! applies. Note that filesystem modules need to prepend their +  //! location to their internal paths. +  //! +  //! @param ret +  //! Result-mapping for the path. +  //! +  //! @seealso +  //! @[Roxen.http_status] +  { +  ASSERT_IF_DEBUG (has_prefix (path, "/")); +  get_multi_status()->add_status (url_base() + path[1..], ret); +  } +  +  // NB: object below to avoid forward reference with variants... +  variant void set_status_for_path (string path, object status) +  //! @decl void set_status_for_path (string path, MultiStatusNode status) +  //! Register a status to be included in the response that applies +  //! only 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 +  //! @[get_multi_status]. +  //! +  //! @param path +  //! Absolute path in the configuration to which the status +  //! applies. Note that filesystem modules need to prepend their +  //! location to their internal paths. +  //! +  //! @param status +  //! Status object for the @[path]. +  //! +  //! @seealso +  //! @[Roxen.http_status] +  { +  ASSERT_IF_DEBUG (has_prefix (path, "/")); +  get_multi_status()->add_status (url_base() + path[1..], status); +  } +     void set_status_for_url (string url, int status_code,    string|void message, mixed... args)    //! Register a status to be included in the response that applies    //! only for the given URL. Similar to @[set_status_for_path], but    //! takes a complete URL instead of an absolute path within the    //! configuration.    {    if (sizeof (args)) message = sprintf (message, @args);    get_multi_status()->add_status (url, status_code, message);    }    -  +  variant void set_status_for_url (string url, mapping(string:mixed) ret) +  //! Register a status to be included in the response that applies +  //! only for the given URL. Similar to @[set_status_for_path], but +  //! takes a complete URL instead of an absolute path within the +  //! configuration. +  { +  get_multi_status()->add_status (url, ret); +  }    -  +  // NB: object below to avoid forward reference with variants... +  variant void set_status_for_url (string url, object status) +  //! @decl void set_status_for_url (string url, MultiStatusNode status) +  //! Register a status to be included in the response that applies +  //! only for the given URL. Similar to @[set_status_for_path], but +  //! takes a complete URL instead of an absolute path within the +  //! configuration. +  { +  get_multi_status()->add_status (url, status); +  } +  +     // Charset handling       array(string) output_charset = ({});       void set_output_charset( string|function to, int|void mode )    {   #ifdef DEBUG    if (stringp (to))    // This will throw an error if the charset is invalid.    Charset.encoder (to);
Roxen.git/server/base_server/prototypes.pike:3513: Inside #if defined(ID_OBJ_DEBUG)
  #ifdef ID_OBJ_DEBUG    + (__marker ? "[" + __marker->count + "]" : "")   #else    + OBJ_COUNT   #endif    );    }   }      //! @appears MultiStatusStatus - class MultiStatusStatus (int http_code, void|string message) + class MultiStatusStatus   {    constant is_status = 1;    -  +  int http_code; +  SimpleNode message; +  +  //! @param http_code +  //! HTTP return code. +  //! +  //! @param message +  //! Description of @[http_code]. +  protected void create(int http_code, void|string message) +  { +  this::http_code = http_code; +  if (message) { +  SimpleNode node = SimpleElementNode("DAV:responsedescription", ([])); +  node->add_child(SimpleTextNode(message||"")); +  this::message = node; +  } +  } +  +  //! @param ret +  //! Result mapping to convert into a @[MultiStatusStatus]. +  //! +  //! The mapping has often been generated by @[Roxen.http_xml_status()]. +  protected variant void create(mapping(string:mixed) ret) +  { +  if (ret->xml) { +  message = ret->xml; +  http_code = ret->error; +  return; +  } +  create(ret->error, ret->rettext); +  } +     void build_response (SimpleElementNode response_node)    {    SimpleElementNode node = SimpleElementNode("DAV:status", ([]));    response_node->add_child (node);    // No use wasting space on a good message in the status node since    // we have it in the responsedescription instead.    node->add_child(SimpleTextNode(sprintf("HTTP/1.1 %d ", http_code)));       if (message) { -  node = SimpleElementNode ("DAV:responsedescription", ([])); -  response_node->add_child (node); -  node->add_child (SimpleTextNode (message)); +  response_node->add_child(message);    }    }       int `== (mixed other)    {    return objectp (other) &&    object_program (other) == this_program &&    other->http_code == http_code &&    other->message == message;    }       int __hash()    { -  return http_code + (message && hash (message)); +  return http_code + (message && hash (message->render_xml()));    }       string _sprintf (int flag)    {    return flag == 'O' &&    sprintf ("MultiStatusStatus(%d,%O)", http_code, message);    }   }      private SimpleElementNode ok_status_node =
Roxen.git/server/base_server/prototypes.pike:3760:    void add_status (string href, int status_code,    void|string message, mixed... args)    //! Add a status for the specified url. The remaining arguments are    //! the same as for @[Roxen.http_status].    {    if (sizeof (args)) message = sprintf (message, @args);    if (!status_code) error("Bad status code!\n");    status_set[href] = MultiStatusStatus (status_code, message);    }    +  variant void add_status(string href, mapping(string:mixed) ret) +  //! Add a status for the specified url. +  //! +  //! @param href +  //! URL the status is for. +  //! +  //! @param ret +  //! Result-mapping for the URL. +  { +  status_set[href] = MultiStatusStatus(ret); +  } +  +  variant void add_status(string href, MultiStatusNode status_node) +  //! Add a status for the specified url. +  //! +  //! @param href +  //! URL that the @[status_node] is for. +  //! +  //! @param status_node +  //! Status for the @[href]. Typically a @[MultiStatusStatus] or +  //! a @[MultiStatusPropStat]. +  //! +  //! This variant makes it easy to transfer nodes beteen +  //! @[MultiStatus] objects. +  { +  status_set[href] = status_node; +  } +     void add_namespace (string namespace)    //! Add a namespace to the generated @tt{<multistatus>@} element.    //! Useful if several properties share a namespace.    {    int ns_count = 0;    string ns_name;    while (args[ns_name = "xmlns:NS" + ns_count]) {    if (args[ns_name] == namespace) return;    ns_count++;    }
Roxen.git/server/base_server/prototypes.pike:3848:    //! @note    //! Note that the segments of the path will be    //! encoded with @[Roxen.http_encode_url()].    void add_status (string path, int status_code,    void|string message, mixed... args)    {    path = map(path/"/", Roxen->http_encode_url)*"/";    MultiStatus::add_status (href_prefix + path, status_code, message, @args);    }    +  //! Add a status for a path.    //! -  +  //! @note +  //! Note that the segments of the path will be +  //! encoded with @[Roxen.http_encode_url()]. +  variant void add_status (string path, mapping(string:mixed) ret) +  { +  path = map(path/"/", Roxen->http_encode_url)*"/"; +  MultiStatus::add_status (href_prefix + path, ret); +  } +  +  //!    void add_namespace (string namespace)    {    MultiStatus::add_namespace (namespace);    }       //!    MultiStatus.Prefixed prefix(string href_prefix) {    return this_program (this_program::href_prefix + href_prefix);    }    }
Roxen.git/server/base_server/prototypes.pike:3892:    mapping(string:mixed) set_property(string prop_name,    string|array(SimpleNode) value);    mapping(string:mixed) set_dead_property(string prop_name,    array(SimpleNode) value);    mapping(string:mixed) remove_property(string prop_name);    mapping(string:mixed) find_properties(string mode,    MultiStatus.Prefixed result,    multiset(string)|void filt);   }    - //! See @[RoxenModule.check_locks]. - enum LockFlag { -  LOCK_NONE = 0, -  LOCK_SHARED_BELOW = 2, -  LOCK_SHARED_AT = 3, -  LOCK_OWN_BELOW = 4, -  LOCK_EXCL_BELOW = 6, -  LOCK_EXCL_AT = 7 - }; -  +    //! How to handle an existing destination when files or directories   //! are moved or copied in a filesystem.   enum Overwrite {    //! Fail if the destination exists. Corresponds to an Overwrite    //! header with the value "F" (RFC 2518 9.6).    NEVER_OVERWRITE = -1,       //! If the source and destination are directories, overwrite the    //! properties only. If the source and destination are files,    //! overwrite the file along with the properties. Otherwise fail if
Roxen.git/server/base_server/prototypes.pike:4046:    array(PatchPropertyCommand) instructions,    RequestID id);    mapping(string:mixed) set_property (string path, string prop_name,    string|array(SimpleNode) value,    RequestID id);    mapping(string:mixed) remove_property (string path, string prop_name,    RequestID id);       string resource_id (string path, RequestID id);    string|int authenticated_user_id (string path, RequestID id); -  multiset(DAVLock) find_locks(string path, +  mapping(string:DAVLock) find_locks(string path,    int(-1..1) recursive,    int(0..1) exclude_shared,    RequestID id); -  DAVLock|LockFlag check_locks(string path, -  int(0..1) recursive, -  RequestID id); +     mapping(string:mixed) lock_file(string path,    DAVLock lock,    RequestID id);    mapping(string:mixed) unlock_file (string path,    DAVLock lock,    RequestID id);    mapping(string:mixed)|int(0..1) check_if_header(string relative_path,    int(0..1) recursive,    RequestID id);       mapping(string:mixed)|int(-1..0)|Stdio.File find_file(string path,    RequestID id);    mapping(string:mixed) recurse_delete_files(string path,    RequestID id);    mapping(string:mixed) make_collection(string path, RequestID id);    mapping(string:mixed) recurse_copy_files(string source, string destination,    PropertyBehavior behavior, -  Overwrite overwrite, RequestID id); +  Overwrite overwrite, RequestID id, +  int|void one_level);    mapping(string:mixed) recurse_move_files(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id);   }      class PatchPropertyCommand   {    constant command = "";    string property_name;    mapping(string:mixed) execute(PropertySet context);