Roxen.git / server / base_server / configuration.pike

version» Context lines:

Roxen.git/server/base_server/configuration.pike:1749:       case 401:    if (m->extra_heads["www-authenticate"])    res = sprintf("Returned authentication failed: %O ",    m->extra_heads["www-authenticate"]);    else    res = "Returned authentication failed. ";    break;       case 200: +  // NB: Note the setting of extra_heads above. +  if (sizeof(m) <= 1) { +  res = "Returned multi status. "; +  break; +  }    res = "Returned ok. ";    break;       default:    res = sprintf("Returned %O. ", m->error);    }       if (!zero_type(m->len))    if (m->len<0)    res += "No data ";
Roxen.git/server/base_server/configuration.pike:1782:       if (stringp(m->extra_heads["content-type"]) ||    stringp(m->type)) {    res += sprintf(" of %O", m->type||m->extra_heads["content-type"]);    }       return res;   }      //! Find all applicable locks for this user on @[path]. - 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)   {    SIMPLE_TRACE_ENTER(0, "find_locks(%O, %O, %O, X)",    path, recursive, exclude_shared); -  multiset(DAVLock) locks = (<>); +  mapping(string:DAVLock) locks = ([]);       foreach(location_module_cache||location_modules(),    [string loc, function func])    {    SIMPLE_TRACE_ENTER(function_object(func),    "Finding locks in %O.", loc);    string subpath;    if (has_prefix(path, loc)) {    // path == loc + subpath.    subpath = path[sizeof(loc)..];    } else if (recursive && has_prefix(loc, path)) {    // loc == path + ignored.    subpath = "/";    } else {    // Does not apply to this location module.    TRACE_LEAVE("Skip this module.");    continue;    }    TRACE_ENTER(sprintf("subpath: %O", subpath),    function_object(func)->find_locks); -  multiset(DAVLock) sub_locks = +  mapping(string:DAVLock) sub_locks =    function_object(func)->find_locks(subpath, recursive,    exclude_shared, id);    TRACE_LEAVE("");    if (sub_locks) {    SIMPLE_TRACE_LEAVE("Got some locks: %O", sub_locks);    locks |= sub_locks;    } else {    TRACE_LEAVE("Got no locks.");    }    }    SIMPLE_TRACE_LEAVE("Returning %O", locks);    return locks;   }    - //! Check if there are any applicable locks for this user on @[path]. - DAVLock|LockFlag check_locks(string path, int(0..1) recursive, RequestID id) + //! Check that all locks that apply to @[path] for the user the request + //! is authenticated as have been mentioned in the if-header. + //! + //! WARNING: This function has some design issues and will very likely + //! get a different interface. Compatibility is NOT guaranteed. + //! + //! @param path + //! Normalized path below the filesystem location. + //! + //! @param recursive + //! If @expr{1@} also check recursively under @[path] for locks. + //! + //! @returns + //! Returns one of + //! @mixed + //! @type int(0..0) + //! Zero if not locked, or all locks were mentioned. + //! @type mapping(zero:zero) + //! An empty mapping if @[recursive] was true and there + //! were unmentioned locks on paths with @[path] as a prefix. + //! The missing locks are registered in the multistatus for + //! the @[id] object. + //! @type mapping(string:mixed) + //! A @[Protocols.HTTP.DAV_LOCKED] error status in all other cases. + //! @endmixed + //! + //! @note + //! @[DAVLock] objects may be created if the filesystem has some + //! persistent storage of them. The default implementation does not + //! store locks persistently. + mapping(string:mixed)|int(-1..0) check_locks(string path, +  int(0..1) recursive, +  RequestID id)   { -  LockFlag state = 0; -  foreach(location_module_cache||location_modules(), -  [string loc, function func]) -  { -  string subpath; -  int check_above; -  if (has_prefix(path, loc)) { -  // path == loc + subpath. -  subpath = path[sizeof(loc)..]; -  } else if (recursive && has_prefix(loc, path)) { -  // loc == path + ignored. -  subpath = ""; -  check_above = 1; -  } else { -  // Does not apply to this location module. -  continue; +  TRACE_ENTER(sprintf("check_locks(%O, %d, X)", path, recursive), this); +  +  mapping(string:DAVLock) locks = find_locks(path, recursive, 0, id); +  // Common case. +  if (!sizeof(locks)) { +  TRACE_LEAVE ("Got no locks."); +  return 0;    } -  int/*LockFlag*/|DAVLock lock_info = -  function_object(func)->check_locks(subpath, recursive, id); -  if (objectp(lock_info)) { -  if (!check_above) { -  return lock_info; -  } else { -  lock_info = LOCK_OWN_BELOW; // We have a lock on some subpath. +  +  mapping(string:array(array(array(string)))) if_data = id->get_if_data(); +  if (if_data) { +  foreach(if_data[0], array(array(string)) tokens) { +  m_delete(locks, tokens[0][1]);    } -  +  +  if (!sizeof(locks)) { +  TRACE_LEAVE ("All locks unlocked."); +  return 0;    } -  else -  if (check_above && (lock_info & 1)) -  // Convert LOCK_*_AT to LOCK_*_BELOW. -  lock_info &= ~1; -  if (lock_info > state) state = lock_info; -  if (state == LOCK_EXCL_AT) return LOCK_EXCL_AT; // Doesn't get any worse. -  if (function_object(func)->webdav_opaque) break; +     } -  return state; +  +  // path = id->not_query; +  if (!has_suffix(path, "/")) path += "/"; +  mapping(string:mixed) ret = +  Roxen.http_dav_error(Protocols.HTTP.DAV_LOCKED, "lock-token-submitted"); +  foreach(locks;;DAVLock lock) { +  TRACE_ENTER(sprintf("Checking lock %O against %O.", lock, path), 0); +  if (has_prefix(path, lock->path)) { +  TRACE_LEAVE("Direct lock."); +  TRACE_LEAVE("Locked."); +  return ret;    } -  +  if (lock->is_file) { +  id->set_status_for_path(lock->path[..<1], ret); +  } else { +  id->set_status_for_path(lock->path, ret); +  } +  TRACE_LEAVE("Added to multi status."); +  } +  TRACE_LEAVE("Multi status."); +  return ([]); + }      protected multiset(DAVLock) active_locks = (<>);      //! Unlock the lock represented by @[lock] on @[path].   //!   //! @returns   //! Returns a result-mapping on error, and @expr{0@} (zero) on success.   mapping(string:mixed) unlock_file(string path, DAVLock lock, RequestID id)   {    // Canonicalize path.
Roxen.git/server/base_server/configuration.pike:1973:   //! Returns a result mapping on failure,   //! and the resulting @[DAVLock] on success.   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)   { +  TRACE_ENTER(sprintf("%O(%O, %O, %O, %O, %O, %O, %O)", +  this_function, path, recursive, lockscope, +  locktype, expiry_delta, owner, id), 0); +  +  int is_file; +     // Canonicalize path. -  if (!has_suffix(path, "/")) path+="/"; +  if (!has_suffix(path, "/")) { +  path+="/"; +  is_file = 1; +  }    -  // First check if there's already some lock on path that prevents +  // FIXME: Race conditions! +  +  int fail; +  +  // First check if there's already some lock on the path that prevents    // us from locking it. -  int/*LockFlag*/|DAVLock lock_info = check_locks(path, recursive, id); +  mapping(string:DAVLock) locks = find_locks(path, recursive, 0, id);    -  if (!intp(lock_info)) { -  // We already hold a lock that prevents us. -  if (id->request_headers->if) { -  return Roxen.http_status(412, "Precondition Failed"); -  } else { -  return Roxen.http_status(423, "Locked"); +  foreach(locks; string lock_token; DAVLock lock) { +  TRACE_ENTER(sprintf("Checking lock %O...\n", lock), 0); +  if ((lock->lockscope == "DAV:exclusive") || +  (lockscope == "DAV:exclusive")) { +  TRACE_LEAVE("Locked."); +  id->set_status_for_path(lock->path, 423, "Locked"); +  fail = 1;    } -  } else if (lockscope == "DAV:exclusive" ? -  lock_info >= LOCK_SHARED_BELOW : -  lock_info >= LOCK_OWN_BELOW) { -  // Some other lock prevents us. -  return Roxen.http_status(423, "Locked"); +  TRACE_LEAVE("Shared.");    }    -  +  if (fail) { +  TRACE_LEAVE("Fail."); +  return ([]); +  } +     // Create the new lock.       string locktoken = "urn:uuid:" + roxen->new_uuid_string();    DAVLock lock = DAVLock(locktoken, path, recursive, lockscope, locktype,    expiry_delta, owner); -  +  lock->is_file = is_file;    foreach(location_module_cache||location_modules(),    [string loc, function func])    {    string subpath;    if (has_prefix(path, loc)) {    // path == loc + subpath.    subpath = path[sizeof(loc)..];    } else if (recursive && has_prefix(loc, path)) {    // loc == path + ignored.    subpath = "/";    } else {    // Does not apply to this location module.    continue;    }    -  +  TRACE_ENTER(sprintf("Calling %O->lock_file(%O, %O, %O)...", +  function_object(func), subpath, lock, id), 0);    mapping(string:mixed) lock_error =    function_object(func)->lock_file(subpath, lock, id);    if (lock_error) {    // Failure. Unlock the new lock.    foreach(location_module_cache||location_modules(),    [string loc2, function func2])    {    if (has_prefix(path, loc2)) {    // path == loc2 + subpath.    mapping(string:mixed) ret =    function_object(func2)->unlock_file(path[sizeof(loc2)..],    lock, id);    } else if (recursive && has_prefix(loc2, path)) {    // loc2 == path + ignored.    mapping(string:mixed) ret =    function_object(func2)->unlock_file("/", lock, id);    }    if (func == func2) break;    }    // destruct(lock); -  +  TRACE_LEAVE(sprintf("Lock error: %O", lock_error));    return lock_error;    } -  +  TRACE_LEAVE("Ok.");    if (function_object(func)->webdav_opaque) break;    }       if (expiry_delta) {    // Lock with timeout.    // FIXME: Race-conditions.    if (!sizeof(active_locks)) {    // Start the lock expiration loop.    active_locks[lock] = 1;    expire_lock_loop();    } else {    active_locks[lock] = 1;    }    }       // Success. -  +  TRACE_LEAVE("Success.");    return lock;   }    -  + //! 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. + //! + //! @seealso + //! @[query_property_set()] + string|array(Parser.XML.Tree.SimpleNode)|mapping(string:mixed) +  query_property(string path, string prop_name, RequestID id) + { +  foreach(location_module_cache||location_modules(), +  [string loc, function func]) +  { +  if (!has_prefix(path, loc)) { +  // Does not apply to this location module. +  continue; +  } +  +  // path == loc + subpath. +  string subpath = path[sizeof(loc)..]; +  +  string|array(Parser.XML.Tree.SimpleNode)|mapping(string:mixed) res = +  function_object(func)->query_property(subpath, prop_name, id); +  if (mappingp(res) && (res->error == 404)) { +  // Not found in this module; try the next. +  continue; +  } +  return res; +  } +  return Roxen.http_status(Protocols.HTTP.HTTP_NOT_FOUND, "No such property."); + } +    mapping|int(-1..0) low_get_file(RequestID id, int|void no_magic)   //! The function that actually tries to find the data requested. All   //! modules except last and filter type modules are mapped, in order,   //! and the first one that returns a suitable response is used. If   //! `no_magic' is set to one, the internal magic roxen images and the   //! @[find_internal()] callbacks will be ignored.   //!   //! The return values 0 (no such file) and -1 (the data is a   //! directory) are only returned when `no_magic' was set to 1;   //! otherwise a result mapping is always generated.
Roxen.git/server/base_server/configuration.pike:2640: Inside #if defined(URL_MODULES)
   if( id->misc->find_dir_nest < 20 )    dir = (id->conf || this_object())->find_dir( file, id );    else    error("Too deep recursion in roxen::find_dir() while mapping "    +file+".\n");    };    id->misc->find_dir_nest = 0;    TRACE_LEAVE("");    if(err)    throw(err); +     if (arrayp(dir)) {    return map(dir, combine_combiners);    }    return dir;    }    TRACE_LEAVE("");    id->not_query=of;    }   #endif /* URL_MODULES */