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 - 2004, Roxen IS. - // $Id: module.pike,v 1.230 2008/05/21 14:50:23 mast Exp $ + // $Id: module.pike,v 1.231 2008/08/15 12:33:53 mast 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:21:   private Configuration _my_configuration;   private string _module_local_identifier;   private string _module_identifier =    lambda() {    mixed init_info = roxen->bootstrap_info->get();    if (arrayp (init_info)) {    [_my_configuration, _module_local_identifier] = init_info;    return _my_configuration->name + "/" + _module_local_identifier;    }    }(); - static mapping _api_functions = ([]); + protected mapping _api_functions = ([]);      string|array(string) module_creator;   string module_url;   RXML.TagSet module_tag_set;      /* These functions exist in here because otherwise the messages in the    * event log do not always end up in the correct module/configuration.    * And the reason for that is that if the messages are logged from    * subclasses in the module, the DWIM in roxenlib.pike cannot see that    * they are logged from a module. This solution is not really all that
Roxen.git/server/base_server/module.pike:166:   }         Configuration my_configuration()   //! Returns the Configuration object of the virtual server the module   //! belongs to.   {    return _my_configuration;   }    - nomask void set_configuration(Configuration c) + final void set_configuration(Configuration c)   {    if(_my_configuration && _my_configuration != c)    error("set_configuration() called twice.\n");    _my_configuration = c;   }      void set_module_creator(string|array(string) c)   //! Set the name and optionally email address of the author of the   //! module. Names on the format "author name <author_email>" will   //! end up as links on the module's information page in the admin
Roxen.git/server/base_server/module.pike:421:    }       TRACE_LEAVE("");    return(res);   }      class DefaultPropertySet   {    inherit PropertySet;    -  static Stat stat; +  protected Stat stat;    -  static void create (string path, string abs_path, RequestID id, Stat stat) +  protected void create (string path, string abs_path, RequestID id, Stat stat)    {    ::create (path, abs_path, id);    this_program::stat = stat;    }       Stat get_stat() {return stat;}    -  static mapping(string:string) response_headers; +  protected mapping(string:string) response_headers;       mapping(string:string) get_response_headers()    {    if (!response_headers) {    // Old kludge inherited from configuration.try_get_file.    if (!id->misc->common)    id->misc->common = ([]);       RequestID sub_id = id->clone_me();    sub_id->misc->common = id->misc->common;
Roxen.git/server/base_server/module.pike:762:   {    // Leave this to the standard auth system by default.    User uid = my_configuration()->authenticate (id);    return uid && uid->name();   }      // Mapping from resource id to a mapping from user id to the lock   // that apply to the resource.   //   // Only used internally by the default lock implementation. - static mapping(string:mapping(mixed:DAVLock)) file_locks = ([]); + protected mapping(string:mapping(mixed:DAVLock)) file_locks = ([]);      // Mapping from resource id to a mapping from user id to the lock   // that apply recursively to the resource and all other resources   // it's a prefix of.   //   // Only used internally by the default lock implementation. - static mapping(string:mapping(mixed:DAVLock)) prefix_locks = ([]); + protected mapping(string:mapping(mixed:DAVLock)) prefix_locks = ([]);      #define LOOP_OVER_BOTH(PATH, LOCKS, CODE) \    do { \    foreach (file_locks; PATH; LOCKS) {CODE;} \    foreach (prefix_locks; PATH; LOCKS) {CODE;} \    } while (0)      //! Find some or all locks that apply to @[path].   //!   //! @param path
Roxen.git/server/base_server/module.pike:1023:   //! Normalized path (below the filesystem location) that the lock   //! applies to.   //!   //! @param lock   //! The lock to register.   //!   //! @note   //! The default implementation only handles the @expr{"DAV:write"@}   //! lock type. It uses @[resource_id] to map paths to unique resources   //! and @[authenticated_user_id] to tell users apart. - static void register_lock(string path, DAVLock lock, RequestID id) + protected void register_lock(string path, DAVLock lock, RequestID id)   {    TRACE_ENTER(sprintf("register_lock(%O, lock(%O), X).", path, lock->locktoken),    this);    ASSERT_IF_DEBUG (lock->locktype == "DAV:write");    mixed auth_user = authenticated_user_id (path, id);    path = resource_id (path, id);    if (lock->recursive) {    if (prefix_locks[path]) {    prefix_locks[path][auth_user] = lock;    } else {
Roxen.git/server/base_server/module.pike:1063:   //! @param path   //! Normalized path (below the filesystem location) that the lock   //! applies to.   //!   //! @param lock   //! The lock to unregister. (It must not be changed or destructed.)   //!   //! @param id   //! The request id may have the value @expr{0@} (zero) if called   //! by @[Configuration()->expire_locks()]. - static void unregister_lock (string path, DAVLock lock, RequestID|int(0..0) id) + protected void unregister_lock (string path, DAVLock lock, +  RequestID|int(0..0) id)   {    TRACE_ENTER(sprintf("unregister_lock(%O, lock(%O), X).", path, lock->locktoken),    this);    mixed auth_user = id && authenticated_user_id (path, id);    path = resource_id (path, id);    DAVLock removed_lock;    if (lock->recursive) {    if (id) {    removed_lock = m_delete(prefix_locks[path], auth_user);    } else {
Roxen.git/server/base_server/module.pike:1321:   //! write access to @[path]. It should at least call   //! @[check_if_header] to check DAV locks. It takes the same arguments   //! and has the same return value as that function.   //!   //! WARNING: This function has some design issues and will very likely   //! get a different interface. Compatibility is NOT guaranteed.   //!   //! A filesystem module should typically put all needed write access   //! checks here and then use this from @[find_file()],   //! @[delete_file()] etc. - static mapping(string:mixed)|int(0..1) write_access(string relative_path, + protected mapping(string:mixed)|int(0..1) write_access(string relative_path,    int(0..1) recursive,    RequestID id)   {    return check_if_header (relative_path, recursive, id);   }      mapping(string:mixed)|int(-1..0)|Stdio.File find_file(string path,    RequestID id);      //! Used by the default @[recurse_delete_files] implementation to   //! delete a file or an empty directory.   //!   //! @returns   //! Returns a 2xx series status mapping on success (typically 204 No   //! Content). Returns 0 if the file doesn't exist. Returns an   //! appropriate status mapping for any other error.   //!   //! @note   //! The default implementation falls back to @[find_file()]. - static mapping(string:mixed) delete_file(string path, RequestID id) + protected mapping(string:mixed) delete_file(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 = "DELETE";    // FIXME: Logging?    return find_file(path, tmp_id) ||    tmp_id->misc->error_code && Roxen.http_status (tmp_id->misc->error_code);   }   
Roxen.git/server/base_server/module.pike:1450:   //! @param destination   //! Destination path below the filesystem location.   //!   //! @param behavior   //! Specifies how to copy properties. See the @[PropertyBehavior]   //! type for details.   //!   //! @returns   //! @expr{0@} (zero) on success or an appropriate status mapping for   //! any error. - static mapping(string:mixed) copy_properties(string source, string destination, -  PropertyBehavior behavior, RequestID id) + protected mapping(string:mixed) 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_property_set(source, id);    PropertySet destination_properties = query_property_set(destination, id);       multiset(string) property_set = source_properties->query_all_properties();    mapping(string:mixed) res;    foreach(property_set; string property_name;) {    SIMPLE_TRACE_ENTER(this, "Copying the property %O.", property_name);
Roxen.git/server/base_server/module.pike:1532:   //! location.   //!   //! @returns   //! Returns a 2xx series status mapping on success (typically 201   //! Created if the destination didn't exist before, or 204 No   //! Content otherwise). Returns 0 if the source doesn't exist.   //! Returns an appropriate status mapping for any other error. That   //! includes an empty mapping in case there's a failure on some   //! subpart or at the destination, to signify a 207 Multi-Status   //! response using the info in @[id->get_multi_status()]. - static mapping(string:mixed) copy_collection(string source, -  string destination, -  PropertyBehavior behavior, -  Overwrite overwrite, -  MultiStatus.Prefixed result, -  RequestID id) + protected mapping(string:mixed) copy_collection( +  string source, string destination, PropertyBehavior behavior, +  Overwrite overwrite, MultiStatus.Prefixed result, RequestID 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.    switch(overwrite) {    case DO_OVERWRITE:    // RFC 2518 8.8.4    // If a resource exists at the destination, and the Overwrite
Roxen.git/server/base_server/module.pike:1635:   //!   //! @param overwrite   //! Specifies how to handle the situation if the destination already   //! exists. See the @[Overwrite] type for details.   //!   //! @returns   //! Returns a 2xx series status mapping on success (typically 201   //! Created if the destination didn't exist before, or 204 No   //! Content otherwise). Returns 0 if the source doesn't exist.   //! Returns an appropriate status mapping for any other error. - static mapping(string:mixed) copy_file(string source, string destination, + protected mapping(string:mixed) copy_file(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    SIMPLE_TRACE_ENTER(this, "copy_file(%O, %O, %O, %O, %O)\n",    source, destination, behavior, overwrite, id);    TRACE_LEAVE("Not implemented.");    return Roxen.http_status (Protocols.HTTP.HTTP_NOT_IMPL);   }      //! Copy a resource recursively from @[source] to @[destination].
Roxen.git/server/base_server/module.pike:1764:   //! exists. See the @[Overwrite] type for details.   //!   //! @returns   //! Returns a 2xx series status mapping on success (typically 201   //! Created if the destination didn't exist before, or 204 No   //! Content otherwise). Returns 0 if the source doesn't exist.   //! Returns an appropriate status mapping for any other error. That   //! includes an empty mapping in case there's a failure on some   //! subpart or at the destination, to signify a 207 Multi-Status   //! response using the info in @[id->get_multi_status()]. - static mapping(string:mixed) move_file(string source, string destination, + protected mapping(string:mixed) move_file(string source, string destination,    PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    // Fall back to find_file().    RequestID tmp_id = id->clone_me();    tmp_id->not_query = query_location() + source;    tmp_id->misc["new-uri"] = query_location() + destination;    tmp_id->request_headers->destination =    id->url_base() + query_location()[1..] + destination;    tmp_id->method = "MOVE";
Roxen.git/server/base_server/module.pike:1821:   //! Created if the destination didn't exist before, or 204 No   //! Content otherwise). Returns 0 if the source doesn't exist.   //! Returns an appropriate status mapping for any other error. That   //! includes an empty mapping in case there's a failure on some   //! subpart or at the destination, to signify a 207 Multi-Status   //! response using the info in @[id->get_multi_status()].   //!   //! @note   //! The function must be prepared to recurse to check DAV locks   //! properly. - static mapping(string:mixed) move_collection(string source, string destination, -  PropertyBehavior behavior, + protected mapping(string:mixed) move_collection( +  string source, string destination, PropertyBehavior behavior,    Overwrite overwrite, RequestID id)   {    // Fall back to find_file().    RequestID tmp_id = id->clone_me();    tmp_id->not_query = query_location() + source;    tmp_id->misc["new-uri"] = query_location() + destination;    tmp_id->request_headers->destination =    id->url_base() + query_location()[1..] + destination;    tmp_id->method = "MOVE";    mapping(string:mixed) res = find_file(source, tmp_id);
Roxen.git/server/base_server/module.pike:1991:    Stdio.File file=Stdio.File();    if(!file->open(path,"r")) return 0;    if(has_suffix(index, "()"))    index = index[..sizeof(index) - 3];       // Pass path to original file so that include statements for local files    // work correctly.    return compile_string((pre || "") + file->read(), path)[index];   }    - static private mapping __my_tables = ([]); + private mapping __my_tables = ([]);      array(mapping(string:mixed)) sql_query( string query, mixed ... args )   //! Do a SQL-query using @[get_my_sql], the table names in the query   //! should be written as &table; instead of table. As an example, if   //! the tables 'meta' and 'data' have been created with create_tables   //! or get_my_table, this query will work:   //!   //! SELECT &meta;.id AS id, &data;.data as DATA   //! FROM &data;, &meta; WHERE &my.meta;.xsize=200   //!   {    return get_my_sql()->query( replace( query, __my_tables ), @args );   }      object sql_big_query( string query, mixed ... args ) - //! Identical to @[sql_query], but the @[Sql.sql()->big_query] method - //! will be used instead of the @[Sql.sql()->query] method. + //! Identical to @[sql_query], but the @[Sql.Sql()->big_query] method + //! will be used instead of the @[Sql.Sql()->query] method.   {    return get_my_sql()->big_query( replace( query, __my_tables ), @args );   }      array(mapping(string:mixed)) sql_query_ro( string query, mixed ... args )   //! Do a read-only SQL-query using @[get_my_sql], the table names in the query   //! should be written as &table; instead of table. As an example, if   //! the tables 'meta' and 'data' have been created with create_tables   //! or get_my_table, this query will work:   //!   //! SELECT &meta;.id AS id, &data;.data as DATA   //! FROM &data;, &meta; WHERE &my.meta;.xsize=200   //!   {    return get_my_sql(1)->query( replace( query, __my_tables ), @args );   }      object sql_big_query_ro( string query, mixed ... args ) - //! Identical to @[sql_query_ro], but the @[Sql.sql()->big_query] method - //! will be used instead of the @[Sql.sql()->query] method. + //! Identical to @[sql_query_ro], but the @[Sql.Sql()->big_query] method + //! will be used instead of the @[Sql.Sql()->query] method.   {    return get_my_sql(1)->big_query( replace( query, __my_tables ), @args );   }    - static int create_sql_tables( mapping(string:array(string)) definitions, -  string|void comment, -  int|void no_unique_names ) + protected int create_sql_tables( mapping(string:array(string)) definitions, +  string|void comment, int|void no_unique_names )   //! Create multiple tables in one go. See @[get_my_table]   //! Returns the number of tables that were actually created.   {    int ddc;    if( !no_unique_names )    foreach( indices( definitions ), string t )    ddc+=get_my_table( t, definitions[t], comment, 1 );    else    {    Sql.Sql sql = get_my_sql();
Roxen.git/server/base_server/module.pike:2058:    if( !catch {    sql->query("CREATE TABLE "+t+" ("+definitions[t]*","+")" );    } )    ddc++;    DBManager.is_module_table( this_object(), my_db, t, comment );    }    }    return ddc;   }    - static string sql_table_exists( string name ) + protected string sql_table_exists( string name )   //! Return the real name of the table 'name' if it exists.   {    if(strlen(name))    name = "_"+name;       string res = hash(_my_configuration->name)->digits(36)    + "_" + replace(sname(), ({ "#","-" }), ({ "_","_" })) + name;       return catch(get_my_sql()->query( "SELECT * FROM "+res+" LIMIT 1" ))?0:res;   }       - static string|int get_my_table( string|array(string) name, + protected string|int get_my_table( string|array(string) name,    void|array(string)|string definition, -  string|void comment, -  int|void flag ) +  string|void comment, int|void flag )   //! @decl string get_my_table( string name, array(string) types )   //! @decl string get_my_table( string name, string definition )   //! @decl string get_my_table( string definition )   //! @decl string get_my_table( array(string) definition )   //!   //! Returns the name of a table in the 'shared' database that is   //! unique for this module. It is possible to select another database   //! by using @[set_my_db] before calling this function.   //!   //! You can use @[create_sql_tables] instead of this function if you want
Roxen.git/server/base_server/module.pike:2184:   // describe_error( error ) );   // }    if( flag )    {    __my_tables[ "&"+oname+";" ] = res;    return ddc;    }    return __my_tables[ "&"+oname+";" ] = res;   }    - static string my_db = "local"; + protected string my_db = "local";    - static void set_my_db( string to ) + protected void set_my_db( string to )   //! Select the database in which tables will be created with   //! get_my_table, and also the one that will be returned by   //! @[get_my_sql]   {    my_db = to;   }      Sql.Sql get_my_sql( int|void read_only, void|string charset )   //! Return a SQL-object for the database set with @[set_my_db],   //! defaulting to the 'shared' database. If @[read_only] is specified,   //! the database will be opened in read_only mode. @[charset] may be   //! used to specify a charset for the connection if the database   //! supports it.   //!   //! See also @[DBManager.get]   {    return DBManager.cached_get( my_db, _my_configuration, read_only, charset );   }