Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2004, Roxen IS.   //   // The Roxen WebServer main program.   //   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.980 2008/08/08 15:04:22 mast Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.981 2008/08/15 12:33:54 mast Exp $";      //! @appears roxen   //!   //! The Roxen WebServer main program.      // The argument cache. Used by the image cache.   ArgCache argcache;      // Some headerfiles   #define IN_ROXEN
Roxen.git/server/base_server/roxen.pike:69:   #if constant(System.dumpable)   #define enable_coredumps(X) System.dumpable(X)   #elif constant(system.dumpable)   // Pike 7.2.   #define enable_coredumps(X) system.dumpable(X)   #else   #define enable_coredumps(X)   #endif      #define DDUMP(X) sol( combine_path( __FILE__, "../../" + X ), dump ) - static function sol = master()->set_on_load; + protected function sol = master()->set_on_load;      #ifdef TEST_EUID_CHANGE   int test_euid_change;   #endif      string md5( string what )   { -  return Gmp.mpz(Crypto.md5()->update( what )->digest(),256) +  return Gmp.mpz(Crypto.MD5()->update( what )->digest(),256)    ->digits(32);   }      string query_configuration_dir()   {    return configuration_dir;   }      string filename( program|object o )   {    if( objectp( o ) )    o = object_program( o );       string fname = master()->program_name( o );    if( !fname )    fname = "Unknown Program";    return fname-(getcwd()+"/");   }    - static int once_mode; + protected int once_mode;      // Note that 2.5 is a nonexisting version. It's only used for the   // cache static optimization for tags such as <if> and <emit> inside   // <cache> since that optimization can give tricky incompatibilities   // with 2.4.   array(string) compat_levels = ({"2.1", "2.2", "2.4", "2.5",    "3.3", "3.4",    "4.0", "4.5", "5.0"});      #ifdef THREADS
Roxen.git/server/base_server/roxen.pike:134:   #endif /* THREADS */      /*    * The privilege changer. Works like a mutex lock, but changes the UID/GID    * while held. Blocks all threads.    *    * Based on privs.pike,v 1.36.    */   int privs_level;    - static class Privs + protected class Privs   {   #if efun(seteuid)       int saved_uid;    int saved_gid;       int new_uid;    int new_gid;      #define LOGP (variables && variables->audit && variables->audit->query())      #if constant(geteuid) && constant(getegid) && constant(seteuid) && constant(setegid)   #define HAVE_EFFECTIVE_USER   #endif    -  static private string _getcwd() +  private string _getcwd()    {    if (catch{return(getcwd());}) {    return("Unknown directory (no x-bit on current directory?)");    }    }    -  static private string dbt(array t) +  private string dbt(array t)    {    if(!arrayp(t) || (sizeof(t)<2)) return "";    return (((t[0]||"Unknown program")-(_getcwd()+"/"))-"base_server/")+":"+t[1]+"\n";    }      #ifdef THREADS -  static mixed mutex_key; // Only one thread may modify the euid/egid at a time. -  static object threads_disabled; +  protected mixed mutex_key; // Only one thread may modify the euid/egid at a time. +  protected object threads_disabled;   #endif /* THREADS */       int p_level;       void create(string reason, int|string|void uid, int|string|void gid)    {    // No need for Privs if the uid has been changed permanently.    if(getuid()) return;      #ifdef PRIVS_DEBUG
Roxen.git/server/base_server/roxen.pike:386:   #endif /* HAVE_EFFECTIVE_USER */    }   #else /* efun(seteuid) */    void create(string reason, int|string|void uid, int|string|void gid){}   #endif /* efun(seteuid) */   }      /* Used by read_config.pike, since there seems to be problems with    * overloading otherwise.    */ - static Privs PRIVS(string r, int|string|void u, int|string|void g) + protected Privs PRIVS(string r, int|string|void u, int|string|void g)   {    return Privs(r, u, g);   }      // Current Configuration.   Thread.Local current_configuration = Thread.Local();      // font cache and loading.   //   // This will be changed to a list of server global modules, to make it
Roxen.git/server/base_server/roxen.pike:613: Inside #if defined(THREADS)
  // // See the discussion below. :-)   //   // // But there is extra functionality below we really want, though,   // // so let's use that one instead...   // function async_sig_start( function f, int really )   // {   // return lambda( mixed ... args ) {   // thread_create( f, @args );   // };   // } - local static Queue handle_queue = Queue(); + local protected Queue handle_queue = Queue();   //! Queue of things to handle.   //! An entry consists of an array(function fp, array args)    - local static int thread_reap_cnt; + local protected int thread_reap_cnt;   //! Number of handler threads in the process of being stopped.    - static int threads_on_hold; + protected int threads_on_hold;   //! Number of handler threads on hold.    - local static void handler_thread(int id) + local protected void handler_thread(int id)   //! The actual handling function. This functions read function and   //! parameters from the queue, calls it, then reads another one. There   //! is a lot of error handling to ensure that nothing serious happens if   //! the handler function throws an error.   {    THREAD_WERR("Handle thread ["+id+"] started");    mixed h, q;    set_u_and_gid (1);   #ifdef TEST_EUID_CHANGE    if (test_euid_change) {
Roxen.git/server/base_server/roxen.pike:726: Inside #if defined(THREADS)
  {    handle_queue->write(({f, args }));   }      int number_of_threads;   //! The number of handler threads to run.      int busy_threads;   //! The number of currently busy threads.    - static array(object) handler_threads = ({}); + protected array(object) handler_threads = ({});   //! The handler threads, the list is kept for debug reasons.      void start_handler_threads()   {    if (query("numthreads") <= 1) {    set( "numthreads", 1 );    report_warning (LOC_S(1, "Starting one thread to handle requests.")+"\n");    } else {    report_notice (LOC_S(2, "Starting %d threads to handle requests.")+"\n",    query("numthreads") );    }    array(object) new_threads = ({});    for(; number_of_threads < query("numthreads"); number_of_threads++)    new_threads += ({ do_thread_create( "Handle thread [" +    number_of_threads + "]",    handler_thread, number_of_threads ) });    handler_threads += new_threads;   }    - static int num_hold_messages; - static Thread.Condition hold_wakeup_cond = Thread.Condition(); + protected int num_hold_messages; + protected Thread.Condition hold_wakeup_cond = Thread.Condition();   // Note: There are races in the use of this condition variable, but   // the only effect of that is that some handler thread might be   // considered hung when it's actually waiting on hold_wakeup_cond, and   // the hold/release handler threads function deal with hung threads   // anyway. The outcome would only be that release_handler_threads   // starts some extra handler thread unnecessarily.      void hold_handler_threads()   //! Tries to put all handler threads on hold, but gives up if it takes   //! too long.
Roxen.git/server/base_server/roxen.pike:827: Inside #if defined(THREADS)
   report_notice ("Created %d new handler threads to compensate "    "for %d blocked ones.\n", threads_to_create, blocked_threads);    }    }    else {    THREAD_WERR("Ignoring request to release handler threads during stop");    return;    }   }    - static Thread.MutexKey backend_block_lock; + protected Thread.MutexKey backend_block_lock;      void stop_handler_threads()   //! Stop all the handler threads and the backend, but give up if it   //! takes too long.   {    int timeout=10;   #if constant(_reset_dmalloc)    // DMALLOC slows stuff down a bit...    timeout *= 10;   #endif /* constant(_reset_dmalloc) */
Roxen.git/server/base_server/roxen.pike:894:   }      // function handle = unthreaded_handle;      #endif /* THREADS */      function async_sig_start( function f, int really )   {    class SignalAsyncVerifier( function f )    { -  static int async_called; +  protected int async_called;       void really_call( array args )    {    async_called = 0;    f( @args );    }       void call( mixed ... args )    {    if( async_called && async_called-time() )
Roxen.git/server/base_server/roxen.pike:963:    //    // I hope that this will solve all your problems. /per    if( really > 0 )    return lambda( mixed ... args ){ call_out( f, 0, @args ); };    if( really < 0 )    return f;    return SignalAsyncVerifier( f )->call;   }      #ifdef THREADS - static Thread.Queue bg_queue = Thread.Queue(); - static int bg_process_running; + protected Thread.Queue bg_queue = Thread.Queue(); + protected int bg_process_running;      // Use a time buffer to strike a balance if the server is busy and   // always have at least one busy thread: The maximum waiting time in   // that case is somewhere between bg_time_buffer_min and   // bg_time_buffer_max. If there are only short periods of time between   // the queue runs, the max waiting time will shrink towards the   // minimum. - static constant bg_time_buffer_max = 30; - static constant bg_time_buffer_min = 0; - static int bg_last_busy = 0; + protected constant bg_time_buffer_max = 30; + protected constant bg_time_buffer_min = 0; + protected int bg_last_busy = 0;    - static void bg_process_queue() + protected void bg_process_queue()   {    if (bg_process_running) return;    // Relying on the interpreter lock here.    bg_process_running = 1;       int maxbeats =    min (time() - bg_last_busy, bg_time_buffer_max) * (int) (1 / 0.04);       if (mixed err = catch {    while (bg_queue->size()) {
Roxen.git/server/base_server/roxen.pike:1135:   //! A class to do a task repeatedly in the background, in a way that   //! makes as little impact as possible on the incoming requests (using   //! @[background_run]).   //!   //! The user must keep a reference to this object, otherwise it will remove   //! itself and the callback won't be called anymore.   {    int|float period;    int stopping = 0;    -  static void repeat (function func, mixed args) +  protected void repeat (function func, mixed args)    {    // Got a minimum of four refs to this:    // o One in the task array in bg_process_queue.    // o One on the stack in the call in bg_process_queue.    // o One as current_object in the stack frame.    // o One on the stack as argument to _refs.    int self_refs = _refs (this);   #ifdef DEBUG    if (self_refs < 4)    error ("Minimum ref calculation wrong - have only %d refs.\n", self_refs);
Roxen.git/server/base_server/roxen.pike:1172:    //! Changes the period to @[period] seconds between calls.    //!    //! @note    //! This does not change the currently ongoing period, if any. That    //! might be remedied.    void set_period (int|float period_)    {    period = period_;    }    -  //! @decl static void create (int|float period, function func, mixed... args); +  //! @decl protected void create (int|float period, function func, mixed... args);    //!    //! The function @[func] will be called with the following arguments    //! after approximately @[period] seconds, and then kept being    //! called with approximately that amount of time between each call.    //!    //! The repetition will stop if @[stop] is called, or if @[func]    //! throws an error. -  static void create (int|float period_, function func, mixed... args) +  protected void create (int|float period_, function func, mixed... args)    {    period = period_;    background_run (period, repeat, func, args);    }       void stop()    //! Sets a flag to stop the succession of calls.    {    stopping = 1;    }
Roxen.git/server/base_server/roxen.pike:1219:    set( "port_options" , q );    save( );   }      #ifdef DEBUG_URL2CONF   #define URL2CONF_MSG(X...) report_debug (X)   #else   #define URL2CONF_MSG(X...)   #endif    - static mapping(string:int(0..1)) host_is_local_cache = ([]); + protected mapping(string:int(0..1)) host_is_local_cache = ([]);      //! Check if @[hostname] is local to this machine.   int(0..1) host_is_local(string hostname)   {    int(0..1) res;    if (!zero_type(res = host_is_local_cache[hostname])) return res;       // Look up the IP.    string ip = blocking_host_to_ip(hostname);   
Roxen.git/server/base_server/roxen.pike:1344:    string path = uri->path;    raw_url = path;    method = "GET";    raw = "GET " + raw_url + " HTTP/1.1\r\n\r\n";    array(Protocol) port_array = ({ 0 });    conf = find_configuration_for_url(uri, 0, port_array);    port_obj = port_array[0];    return set_path( raw_url );    }    -  static string _sprintf() +  protected string _sprintf()    {    return sprintf("RequestID(conf=%O; not_query=%O)", conf, not_query );    }    -  static void create() +  protected void create()    {    client = ({ "Roxen" });    prot = "INTERNAL";    method = "GET";    real_variables = ([]);    variables = FakedVariables( real_variables );    root_id = this_object();       misc = ([ "pref_languages": PrefLanguages(),    "cacheable": INITIAL_CACHEABLE,
Roxen.git/server/base_server/roxen.pike:1381:    extra_extension = "";    remoteaddr = "127.0.0.1";    }   }      class Protocol   //! The basic protocol.   //! Implements reference handling, finding Configuration objects   //! for URLs, and the bind/accept handling.   { -  static Stdio.Port port_obj; +  protected Stdio.Port port_obj;       inherit "basic_defvar";    int bound;       string path;    constant name = "unknown";    constant supports_ipless = 0;    //! If true, the protocol handles ip-less virtual hosting       constant requesthandlerfile = "";
Roxen.git/server/base_server/roxen.pike:1519:    return port_obj->accept();    }       string query_address()    {    return port_obj && port_obj->query_address();    }       mapping mu;    string rrhf; -  static void got_connection() +  protected void got_connection()    {    Stdio.File q;    while( q = accept() )    {    if( !requesthandler && rrhf )    {    requesthandler = (program)(rrhf);    }    Configuration c;    if( refs < 2 )
Roxen.git/server/base_server/roxen.pike:1684:    map(indices(variables),query)));    }       void restore()    //! Restore all port options from saved values    {    foreach( (array)get_port_options( get_key() ), array kv )    set( kv[0], kv[1] );    }    -  static int retries; -  static void bind (void|int ignore_eaddrinuse) +  protected int retries; +  protected void bind (void|int ignore_eaddrinuse)    {    if (bound) return;    if (!port_obj) port_obj = Stdio.Port();    Privs privs = Privs (sprintf ("Binding %s", get_url()));    if (port_obj->bind(port, got_connection, ip))    {    privs = 0;    bound = 1;    return;    }
Roxen.git/server/base_server/roxen.pike:1732:   #endif /* constant(System.EADDRINUSE) || constant(system.EADDRINUSE) */    {    report_error(LOC_M(6, "Failed to bind %s (%s)")+"\n",    get_url(), strerror(port_obj->errno()));   #if 0    werror (describe_backtrace (backtrace()));   #endif    }    }    -  static array(int) get_ipv6_sequence(string partition) +  protected array(int) get_ipv6_sequence(string partition)    {    array(int) segments = ({});    foreach(partition/":", string part) {    if (has_value(part, ".")) {    array(int) sub_segs = array_sscanf(part, "%d.%d.%d.%d");    switch(sizeof(sub_segs)) {    default:    case 4:    segments += ({ sub_segs[0]*256+sub_segs[1],    sub_segs[2]*256+sub_segs[3] });
Roxen.git/server/base_server/roxen.pike:1840:    * work addresses as 128.net.host.    */    bytes = sprintf("%1c%1c%2c", @segments);    break;    }    if (bytes == "\0\0\0\0") return 0; // ANY.    return sprintf("%d.%d.%d.%d", @((array(int))bytes));    }    }    -  static void setup (int pn, string i) +  protected void setup (int pn, string i)    {    port = pn;    ip = canonical_ip(i);       restore();    if (sizeof(requesthandlerfile)) {    if( file_stat( "../local/"+requesthandlerfile ) )    rrhf = "../local/"+requesthandlerfile;    else    rrhf = requesthandlerfile;
Roxen.git/server/base_server/roxen.pike:1862: Inside #if defined(DEBUG)
  #ifdef DEBUG    if( !requesthandler )    requesthandler = (program)(rrhf);   #endif    }    bound = 0;    port_obj = 0;    retries = 0;    }    -  static void create( int pn, string i, void|int ignore_eaddrinuse ) +  protected void create( int pn, string i, void|int ignore_eaddrinuse )    //! Constructor. Bind to the port 'pn' ip 'i'    {    setup (pn, i);    bind (ignore_eaddrinuse);    }    -  static string _sprintf( ) +  protected string _sprintf( )    {    return "Protocol(" + get_url() + ")";    }   }      #if constant(SSL.sslfile)   class SSLProtocol   //! Base protocol for SSL ports. Exactly like Port, but uses SSL.   {    inherit Protocol;       // SSL context    SSL.context ctx = SSL.context();       int cert_failure;    -  static void cert_err_unbind() +  protected void cert_err_unbind()    {    if (bound) {    port_obj->close();    report_warning ("TLS port %s closed.\n", get_url());    bound = 0;    }    }      #define CERT_WARNING(VAR, MSG, ARGS...) do { \    string msg = (MSG); \
Roxen.git/server/base_server/roxen.pike:1914:    string msg = (MSG); \    array args = ({ARGS}); \    if (sizeof (args)) msg = sprintf (msg, @args); \    report_error ("TLS port %s: %s", get_url(), msg); \    (VAR)->add_warning (msg); \    cert_err_unbind(); \    cert_failure = 1; \    return; \    } while (0)    -  void certificates_changed(Variable|void ignored, +  void certificates_changed(Variable.Variable|void ignored,    void|int ignore_eaddrinuse)    {    int old_cert_failure = cert_failure;       string raw_keydata;    array(string) certificates = ({});    array(object) decoded_certs = ({}); -  Variable Certificates = getvar("ssl_cert_file"); +  Variable.Variable Certificates = getvar("ssl_cert_file");       object privs = Privs("Reading cert file");       foreach(map(Certificates->query(), String.trim_whites), string cert_file) {    string raw_cert;    SSL3_WERR (sprintf ("Reading cert file %O", cert_file));    if( catch{ raw_cert = lopen(cert_file, "r")->read(); } )    {    CERT_WARNING (Certificates,    LOC_M(8, "Reading certificate file %O failed: %s\n"),
Roxen.git/server/base_server/roxen.pike:1974:    }       if (!sizeof(decoded_certs)) {    report_error ("TLS port %s: %s", get_url(),    LOC_M(63,"No certificates found.\n"));    cert_err_unbind();    cert_failure = 1;    return;    }    -  Variable KeyFile = getvar("ssl_key_file"); +  Variable.Variable KeyFile = getvar("ssl_key_file");       if( strlen(KeyFile->query())) {    SSL3_WERR (sprintf ("Reading key file %O", KeyFile->query()));    if (catch{ raw_keydata = lopen(KeyFile->query(), "r")->read(); } )    CERT_ERROR (KeyFile,    LOC_M(9, "Reading key file %O failed: %s\n"),    KeyFile->query(), strerror (errno()));    }    else    KeyFile = Certificates;
Roxen.git/server/base_server/roxen.pike:2016:    CERT_ERROR (KeyFile,    LOC_M(11,"Private rsa key not valid")+" (DER).\n");       ctx->rsa = rsa;       SSL3_WERR(sprintf("RSA key size: %d bits", rsa->rsa_size()));       if (rsa->rsa_size() > 512)    {    /* Too large for export */ - #if constant(Crypto.RSA) +     ctx->short_rsa = Crypto.RSA()->generate_key(512, ctx->random); - #else -  ctx->short_rsa = Crypto.rsa()->generate_key(512, ctx->random); - #endif +     -  // ctx->long_rsa = Crypto.rsa()->generate_key(rsa->rsa_size(), ctx->random); +  // ctx->long_rsa = Crypto.RSA()->generate_key(rsa->rsa_size(), ctx->random);    }    ctx->rsa_mode();       array(int) key_matches =    map(decoded_certs,    lambda (object tbs) {    return tbs->public_key->rsa->public_key_equal (rsa);    });       int num_key_matches;
Roxen.git/server/base_server/roxen.pike:2120:    inherit Variable.String;       string doc()    {    return sprintf(::doc() + "\n",    combine_path(getcwd(), "../local"),    getcwd());    }    }    -  RoxenSSLFile accept() +  SSL.sslfile accept()    {    Stdio.File q = ::accept();    if (q) -  return RoxenSSLFile (q, ctx); +  return SSL.sslfile (q, ctx);    return 0;    }    -  static void bind (void|int ignore_eaddrinuse) +  protected void bind (void|int ignore_eaddrinuse)    {    // Don't bind if we don't have correct certs.    if (!ctx->certificates) return;    ::bind (ignore_eaddrinuse);    }       void create(int pn, string i, void|int ignore_eaddrinuse)    { - #if constant(Crypto.Random.random_string) +     ctx->random = Crypto.Random.random_string; - #else -  ctx->random = Crypto.randomness.reasonably_random()->read; - #endif +        set_up_ssl_variables( this_object() );       ::setup(pn, i);       certificates_changed (0, ignore_eaddrinuse);       // Install the change callbacks here to avoid duplicate calls    // above.    // FIXME: Both variables ought to be updated on save before the
Roxen.git/server/base_server/roxen.pike:2175:      mapping(string:Protocol) build_protocols_mapping()   {    mapping protocols = ([]);    int st = gethrtime();    report_debug("Protocol handlers ... \b");   #ifndef DEBUG    class lazy_load( string prog, string name )    {    program real; -  static void realize() +  protected void realize()    {    if( catch {    DDUMP( prog );    real = (program)prog;    protocols[name] = real;    } )    report_error("Failed to compile protocol handler for "+name+"\n");    }       Protocol `()(mixed ... x)
Roxen.git/server/base_server/roxen.pike:2602:    {    if( (lower_case( replace( replace(o->name, "-"," ") - " " ,    "/", "-" ) ) == name) ||    (lower_case( replace( replace(o->query_name(), "-", " ") - " " ,    "/", "-" ) ) == name) )    return o;    }    return 0;   }    - static int last_hrtime = gethrtime(1)/100; - static int clock_sequence = random(0x4000); - static string hex_mac_address = -  Crypto.string_to_hex(Crypto.randomness.reasonably_random()->read(6)| + protected int last_hrtime = gethrtime(1)/100; + protected int clock_sequence = random(0x4000); + protected string hex_mac_address = +  String.string2hex(Crypto.Random.random_string (6)|    "\1\0\0\0\0\0"); // Multicast bit.   // Generate an uuid string.   string new_uuid_string()   {    int now = gethrtime(1)/100;    if (now != last_hrtime) {    clock_sequence = random(0x4000);    last_hrtime = now;    }    int seq = clock_sequence++;
Roxen.git/server/base_server/roxen.pike:2758: Inside #if ROXEN_COMPAT < 2.2
   current_user_id_file->seek(0);    current_user_id_file->write((string)current_user_id_number);    current_user_id_file_last_mod = current_user_id_file->stat()[2];    return current_user_id_number;   }   #endif // ROXEN_COMPAT < 2.2      private int unique_id_counter;   string create_unique_id()   { -  object md5 = Crypto.md5(); +  Crypto.MD5 md5 = Crypto.MD5();    md5->update(query("server_salt") + start_time + "|" +    (unique_id_counter++) + "|" + time(1)); -  return Crypto.string_to_hex(md5->digest()); +  return String.string2hex(md5->digest());   }      #ifndef __NT__ - static int abs_started; - static int handlers_alive; + protected int abs_started; + protected int handlers_alive;    - static void low_engage_abs() + protected void low_engage_abs()   {    report_debug("**** %s: ABS exiting roxen!\n\n",    ctime(time()) - "\n");    _exit(1); // It might not quit correctly otherwise, if it's    // locked up   }    - static void engage_abs(int n) + protected void engage_abs(int n)   {    if (!query("abs_engage")) {    abs_started = 0;    report_debug("Anti-Block System Disabled.\n");    return;    }    report_debug("**** %s: ABS engaged!\n"    "Waited more than %d minute(s).\n",    ctime(time()) - "\n",    query("abs_timeout"));
Roxen.git/server/base_server/roxen.pike:2876:    string documentation(void|string tag_n_args)    {    string doc = Stdio.read_file("base_server/image_cache.xml");    if(!doc) return "";    if(!tag_n_args)    return Parser.HTML()->add_container("ex", "")->    add_quote_tag("!--","","--")->finish(doc)->read();    return replace(doc, "###", tag_n_args);    }    -  static mapping meta_cache_insert( string i, mapping what ) +  protected mapping meta_cache_insert( string i, mapping what )    {   #ifdef ARG_CACHE_DEBUG    werror("MD insert for %O: %O\n", i, what );   #endif    if( sizeof( meta_cache ) > 1000 )    sync_meta();    if( what ) {    meta_cache[i] = ({ what, 0 });    return what;    }    else    m_delete( meta_cache, i );    return 0;    }    -  static mixed frommapp( mapping what ) +  protected mixed frommapp( mapping what )    {    if( !what )    error( "Got invalid argcache-entry\n" );    if( !zero_type(what[""]) ) return what[""];    return what;    }    -  static void|mapping draw( string name, RequestID id ) +  protected void|mapping draw( string name, RequestID id )    {   #ifdef ARG_CACHE_DEBUG    werror("draw %O\n", name );   #endif    mixed args = Array.map( Array.map( name/"$", argcache->lookup,    id->client ), frommapp);       mapping meta;    string data;    array guides;
Roxen.git/server/base_server/roxen.pike:3417:    // Avoid throwing and error if the same image is rendered twice.    mixed err = catch(store_data( name, data, meta ));   #ifdef ARG_CACHE_DEBUG    if (err) {    werror("store_data failed with:\n"    "%s\n", describe_backtrace(err));    }   #endif    }    -  static void store_data( string id, string data, mapping meta ) +  protected void store_data( string id, string data, mapping meta )    {    if(!stringp(data)) return;   #ifdef ARG_CACHE_DEBUG    werror("store %O (%d bytes)\n", id, strlen(data) );   #endif    meta_cache_insert( id, meta );    string meta_data = encode_value( meta );   #ifdef ARG_CACHE_DEBUG    werror("Replacing entry for %O\n", id );   #endif
Roxen.git/server/base_server/roxen.pike:3452: Inside #if defined(ARG_CACHE_DEBUG)
   meta_data, q[0]->meta);    }    if (q[0]->data != data) {    werror("Data differs: %O != %O\n",    data, q[0]->data);    }    }   #endif    }    -  static mapping restore_meta( string id, RequestID rid ) +  protected mapping restore_meta( string id, RequestID rid )    {    if( array item = meta_cache[ id ] )    {    item[ 1 ] = time(1); // Update cached atime.    return item[ 0 ];    }      #ifdef ARG_CACHE_DEBUG    werror("restore meta %O\n", id );   #endif
Roxen.git/server/base_server/roxen.pike:3482:    {    report_error( "Corrupt data in cache-entry "+id+".\n" );    QUERY( "DELETE FROM "+name+" WHERE id=%s", id);    return 0;    }       QUERY("UPDATE "+name+" SET atime=UNIX_TIMESTAMP() WHERE id=%s",id );    return meta_cache_insert( id, m );    }    -  static void sync_meta() +  protected void sync_meta()    {    // Sync cached atimes.    foreach(meta_cache; string id; array value) {    if (value[1])    QUERY("UPDATE "+name+" SET atime=%d WHERE id=%s",    value[1], id);    }    meta_cache = ([]);    }   
Roxen.git/server/base_server/roxen.pike:3578:    size += (int)qq->Data_length;    }       if(age) {    q=QUERY("select SUM(1) as num from "+name+" where atime < "+age);    aged = (int)q[0]->num;    }    return ({ imgs, size, aged });    }    -  static mapping(string:mapping) rst_cache = ([ ]); -  static mapping(string:string) uid_cache = ([ ]); +  protected mapping(string:mapping) rst_cache = ([ ]); +  protected mapping(string:string) uid_cache = ([ ]);    -  static mapping restore( string id, RequestID rid ) +  protected mapping restore( string id, RequestID rid )    {    array q;    string uid;    if( zero_type(uid = uid_cache[id]) )    {    q = QUERY( "SELECT uid FROM "+name+" WHERE id=%s",id);    if( sizeof(q) )    uid = q[0]->uid;    else    uid = 0;
Roxen.git/server/base_server/roxen.pike:3829:   #endif /* NO_ARG_CACHE_SB_REPLICATE */    return ci;    }       void set_draw_function( function to )    //! Set a new draw function.    {    draw_function = to;    }    -  static void setup_tables() +  protected void setup_tables()    {    if(catch(QUERY("SELECT data FROM "+name+" WHERE id=''")))    {    werror("Creating image-cache tables for '"+name+"'\n");    catch(QUERY("DROP TABLE "+name));       // The old tables. This is only useful for people who have run    // Roxen 2.2 from cvs before    catch(QUERY("DROP TABLE "+name+"_data"));   
Roxen.git/server/base_server/roxen.pike:3861:    "INDEX atime (atime)"    ")" );    }    }       Sql.Sql get_db()    {    return dbm_cached_get("local");    }    -  static void init_db( ) +  protected void init_db( )    {    catch(sync_meta());    setup_tables();    }       void do_cleanup( )    {    // Flushes may be costly in large sites (at least the OPTIMIZE TABLE    // command) so schedule next run sometime after 04:30 the day after    // tomorrow.
Roxen.git/server/base_server/roxen.pike:3939:    Thread.Mutex mutex = Thread.Mutex();    // Allow recursive locks, since it's normal here.   # define LOCK() mixed __ = mutex->lock (2)      #ifdef ARGCACHE_DEBUG   #define dwerror(ARGS...) werror(ARGS)   #else   #define dwerror(ARGS...) 0   #endif    -  static mapping(string|int:mixed) cache = ([ ]); +  protected mapping(string|int:mixed) cache = ([ ]);    -  static void setup_table() +  protected void setup_table()    {    // New style argument2 table.    if(catch(QUERY("SELECT id FROM "+name+"2 LIMIT 0")))    {    master()->resolv("DBManager.is_module_table")    ( 0, "local", name+"2",    "The argument cache, used to map between "    "a unique string and an argument mapping" );    catch(QUERY("DROP TABLE "+name+"2" ));    QUERY("CREATE TABLE "+name+"2 ("
Roxen.git/server/base_server/roxen.pike:3978:    array(mapping(string:mixed)) res =    QUERY("DESCRIBE "+name+"2 contents");       if(res[0]->Type == "blob") {    QUERY("ALTER TABLE "+name+"2 MODIFY contents MEDIUMBLOB NOT NULL");    werror("ArgCache: Extending \"contents\" field in table \"%s2\" from BLOB to MEDIUMBLOB.\n", name);    }    };    }    -  static void init_db() +  protected void init_db()    {    // Delay DBManager resolving to before the 'roxen' object is    // compiled.    cache = ([]);    db = dbm_cached_get("local");    setup_table( );    }    -  static void create( string _name ) +  protected void create( string _name )    {    name = _name;    init_db();    // Support that the 'local' database moves (not really nessesary,    // but it won't hurt either)    master()->resolv( "DBManager.add_dblist_changed_callback" )( init_db );    get_plugins();    }    -  static string read_encoded_args( string id, int dont_update_atime ) +  protected string read_encoded_args( string id, int dont_update_atime )    {    LOCK();    array res = QUERY("SELECT contents FROM "+name+"2 "    " WHERE id = %s", id);    if(!sizeof(res))    return 0;    if (!dont_update_atime)    QUERY("UPDATE "+name+"2 "    " SET atime = NOW() "    " WHERE id = %s", id);    return res[0]->contents;    }    -  static void create_key( string id, string encoded_args ) +  protected void create_key( string id, string encoded_args )    {    LOCK();    array(mapping) rows =    QUERY("SELECT id, contents FROM "+name+"2 WHERE id = %s", id );    foreach( rows, mapping row )    if( row->contents != encoded_args ) {    report_error("ArgCache.create_key(): "    "Duplicate key found! Please report this to support@roxen.com: "    "id: %O, old data: %O, new data: %O\n",    id, row->contents, encoded_args);
Roxen.git/server/base_server/roxen.pike:4041:       QUERY( "INSERT INTO "+name+"2 "    "(id, contents, ctime, atime) VALUES "    "(%s, " MYSQL__BINARY "%s, NOW(), NOW())", id, encoded_args );       dwerror("ArgCache: Create new key %O\n", id);       (plugins->create_key-({0}))( id, encoded_args );    }    -  static array plugins; -  static void get_plugins() +  protected array plugins; +  protected void get_plugins()    {    plugins = ({});    foreach( ({ "../local/arg_cache_plugins", "arg_cache_plugins" }), string d)    if( file_stat( d ) )    foreach( glob("*.pike", get_dir( d )), string f )    {    object plug = ((program)(d+"/"+f))(this_object());    if( !plug->disabled )    plugins += ({ plug });    }    }    -  static mapping plugins_read_encoded_args( string id ) +  protected mapping plugins_read_encoded_args( string id )    {    mapping args;    foreach( (plugins->read_encoded_args - ({0})), function(string:mapping) f )    if( args = f( id ) )    return args;    return 0;    }       string store( mapping args )    //! Store a mapping (of purely encode_value:able data) in the    //! argument cache. The string returned is your key to retrieve the    //! data later.    {    string encoded_args = encode_value_canonic( args ); -  string id = Gmp.mpz(Crypto.sha()->update(encoded_args)->digest(), 256)->digits(36); +  string id = Gmp.mpz(Crypto.SHA1()->update(encoded_args)->digest(), 256)->digits(36);    if( cache[ id ] )    return id;    create_key(id, encoded_args);    if( !cache[ id ] )    cache[ id ] = args+([]);    if( sizeof( cache ) >= CACHE_SIZE )    cache = ([]);    return id;    }   
Roxen.git/server/base_server/roxen.pike:4297:    __REG_PROJ("roxen_""config", "translations/%L/roxen_config.xml");    __REG_PROJ("roxen_""message", "translations/%L/roxen_message.xml");    __REG_PROJ("admin_""tasks", "translations/%L/admin_tasks.xml");    Locale.set_default_project_path("translations/%L/%P.xml");   #undef __REG_PROJ       define_global_variables();       // for module encoding stuff    - #if constant (Protocols.LDAP.SEARCH_RETURN_DECODE_ERRORS) +     // Pike 7.7 or later - we use the native LDAP module and link the    // migration alias NewLDAP to it.    add_constant ("NewLDAP", Protocols.LDAP); - #else -  // Older pike - use our own LDAP protocol as NewLDAP. -  add_constant ("NewLDAP", _NewLDAP); - #endif +        add_constant( "CFUserDBModule",config_userdb_module );       //add_constant( "ArgCache", ArgCache );    //add_constant( "roxen.load_image", load_image );       if (all_constants()["roxen"]) {    error("Duplicate Roxen object!\n");    }   
Roxen.git/server/base_server/roxen.pike:4715:   void enable_configurations_modules()   {    if( all_modules_loaded++ ) return;    foreach(configurations, Configuration config)    if(mixed err=catch( config->enable_all_modules() ))    report_error(LOC_M(36, "Error while loading modules in "    "configuration %s%s"),    config->name+":\n", describe_backtrace(err)+"\n");   }    - mapping low_decode_image(string data, void|mixed tocolor) + mapping low_decode_image(string data)   { -  mapping w = Image._decode( data, tocolor ); +  mapping w = Image._decode( data );    if( w->image ) return w;    return 0;   }      constant decode_layers = Image.decode_layers;      mapping low_load_image(string f, RequestID id, void|mapping err)   {    string data;    if(id->misc->_load_image_called < 5)
Roxen.git/server/base_server/roxen.pike:4967:    cdt_next_seq_dump = time (1) + cdt_dump_seq_interval;    }    }    }    }    sleep (cdt_poll_interval);    }    cdt_thread = 0;   }    - void cdt_changed (Variable v) + void cdt_changed (Variable.Variable v)   {    if (cdt_directory && v->query() && !cdt_thread)    cdt_thread = Thread.thread_create (cdt_poll_file);   }      // ----------------------------------------         constant dump = roxenloader.dump;   
Roxen.git/server/base_server/roxen.pike:5019: Inside #if defined(TIMERS)
   for( int i = 0; i<sizeof(b); i++ )    report_notice( " %-30s : %10.1fms\n", b[i], a[i]/1000.0 );    report_notice("\n\n");   }   #endif         class GCTimestamp   {    array self_ref; -  static void create() {self_ref = ({this_object()});} -  static void destroy() { +  protected void create() {self_ref = ({this_object()});} +  protected void destroy() {    werror ("GC runs at %s", ctime(time()));    GCTimestamp();    }   }         array argv;   int main(int argc, array tmp)   {    // __builtin.gc_parameters((["enabled": 0]));
Roxen.git/server/base_server/roxen.pike:5320:      void restart_suicide_checker()   {    remove_call_out(check_commit_suicide);    remove_call_out(check_suicide);    call_out(check_suicide, 60);    call_out(check_commit_suicide, 180); // Minimum uptime: 3 minutes.   }      #ifdef ROXEN_DEBUG_MEMORY_TRACE - static object roxen_debug_info_obj; + protected object roxen_debug_info_obj;   void restart_roxen_debug_memory_trace()   {    remove_call_out(restart_roxen_debug_memory_trace);       if (!roxen_debug_info_obj) {    roxen_debug_info_obj = ((program)"config_interface/actions/debug_info.pike"   )();    }    int t = time();    string html = roxen_debug_info_obj->parse((["real_variables":([])]));
Roxen.git/server/base_server/roxen.pike:5391:    }   }      int is_ip(string s)   {    return s &&    ((sscanf(s,"%*d.%*d.%*d.%*d")==4 && s[-1]>='0' && s[-1]<='9') || // IPv4    (sizeof(s/":") > 1)); // IPv6   }    - static string _sprintf( ) + protected string _sprintf( )   {    return "roxen";   }         // Logging    - class LogFormat // Note: Dumping won't work if static. + class LogFormat // Note: Dumping won't work if protected.   { -  static string url_encode (string str) +  protected string url_encode (string str)    {    // Somewhat like Roxen.http_encode_url, but only encode enough    // chars to avoid ambiguity in typical log formats. Notably, UTF-8    // encoded chars aren't URL encoded too, to make the log easier to    // view in any UTF-8 aware editor or viewer.    return replace (    string_to_utf8 (str), ({    // Control chars.    "\000", "\001", "\002", "\003", "\004", "\005", "\006", "\007",    "\010", "\011", "\012", "\013", "\014", "\015", "\016", "\017",
Roxen.git/server/base_server/roxen.pike:5431:    "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",    "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f",    "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",    "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",    "%7f",    "%25",    "%20", "%22", "%27",    }));    }    -  static int rusage_time; -  static array(int) rusage_data; -  static void update_rusage() +  protected int rusage_time; +  protected mapping(string:int) rusage_data; +  protected void update_rusage()    {    if(!rusage_data || time(1) != rusage_time)    { -  rusage_data = rusage(); +  rusage_data = (["utime": 1, "stime": 1]) & System.getrusage();    rusage_time = time(1);    }    }    -  static int server_cputime() +  protected int server_cputime()    {    update_rusage(); -  if(rusage_data && sizeof(rusage_data) >= 2) -  return rusage_data[0] + rusage_data[1]; +  if(rusage_data) +  return rusage_data->utime + rusage_data->stime;    return 0;    }    -  static int server_usertime() +  protected int server_usertime()    {    update_rusage(); -  if(rusage_data && sizeof(rusage_data) >= 1) -  return rusage_data[0]; +  if(rusage_data) +  return rusage_data->utime;    return 0;    }    -  static int server_systime() +  protected int server_systime()    {    update_rusage(); -  if(rusage_data && sizeof(rusage_data) >= 2) -  return rusage_data[1]; +  if(rusage_data) +  return rusage_data->stime;    return 0;    }    -  static string std_date(mapping(string:int) ct) { +  protected string std_date(mapping(string:int) ct) {    return(sprintf("%04d-%02d-%02d",    1900+ct->year,ct->mon+1, ct->mday));    }    -  static string std_time(mapping(string:int) ct) { +  protected string std_time(mapping(string:int) ct) {    return(sprintf("%02d:%02d:%02d",    ct->hour, ct->min, ct->sec));    }       // CERN date formatter. Note similar code in Roxen.pmod.    -  static constant months = ({ "Jan", "Feb", "Mar", "Apr", "May", "Jun", +  protected constant months = ({ "Jan", "Feb", "Mar", "Apr", "May", "Jun",    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" });    -  static int chd_lt; -  static string chd_lf; +  protected int chd_lt; +  protected string chd_lf;    -  static string cern_http_date(int t, mapping(string:int) ct) +  protected string cern_http_date(int t, mapping(string:int) ct)    {    if( t == chd_lt )    // Interpreter lock assumed here.    return chd_lf;       string c;    int tzh = ct->timezone/3600;    if(tzh > 0)    c="-";    else {
Roxen.git/server/base_server/roxen.pike:5510:    ct->mday, months[ct->mon], 1900+ct->year,    ct->hour, ct->min, ct->sec, c, tzh);       chd_lt = t;    // Interpreter lock assumed here.    chd_lf = c;       return c;    }    -  static string host_ip_to_int(string s) +  protected string host_ip_to_int(string s)    {    int a, b, c, d;    sscanf(s, "%d.%d.%d.%d", a, b, c, d);    return sprintf("%c%c%c%c",a, b, c, d);    }    -  static string extract_user(string from) +  protected string extract_user(string from)    {    array tmp;    if (!from || sizeof(tmp = from/":")<2)    return "-";    return tmp[0]; // username only, no password    }       void log_access( function do_write, RequestID id, mapping file );       void log_event (function do_write, string facility, string action,    string resource, mapping(string:mixed) info);    -  static void do_async_write( string host, string data, string ip, function c ) +  protected void do_async_write( string host, string data, +  string ip, function c )    {    if( c )    c( replace( data, "\4711", (host||ip) ) );    }   }    - static mapping(string:function) compiled_log_access = ([ ]); - static mapping(string:function) compiled_log_event = ([ ]); + protected mapping(string:function) compiled_log_access = ([ ]); + protected mapping(string:function) compiled_log_event = ([ ]);      #define LOG_ASYNC_HOST 1   #define LOG_NEED_COOKIES 2   #define LOG_NEED_TIMESTAMP 4   #define LOG_NEED_LTIME (8 | LOG_NEED_TIMESTAMP)   #define LOG_NEED_GTIME (16 | LOG_NEED_TIMESTAMP)      // Elements of a format array arr:   // arr[0]: sprintf format for acccess logging (run_log_format).   // arr[1]: Code for the corresponding sprintf argument of arr[0].   // arr[2]: sprintf format for event logging (run_log_event_format).   // May be 0 to reuse arr[0] and arr[1].   // May be 1 to indicate that an attempt is made to look up the   // variable in the info mapping. If it isn't found then arr[3] is   // used as fallback. The sprintf format string is always "%s" in   // this case.   // arr[3]: Code for the corresponding sprintf argument of arr[2].   // arr[4]: Flags.    - static constant formats = ([ + protected constant formats = ([       // Used for both access and event logging    "date": ({"%s", "std_date (ltime)", 0, 0, LOG_NEED_LTIME}),    "time": ({"%s", "std_time (ltime)", 0, 0, LOG_NEED_LTIME}),    "cern-date": ({"%s", "cern_http_date (timestamp, ltime)",    0, 0, LOG_NEED_LTIME}),    "utc-date": ({"%s", "std_date (gtime)", 0, 0, LOG_NEED_GTIME}),    "utc-time": ({"%s", "std_time (gtime)", 0, 0, LOG_NEED_GTIME}),    "bin-date": ({"%4c", "timestamp", 0, 0, LOG_NEED_TIMESTAMP}),    // FIXME: There is no difference between $resource and $full-resource.
Roxen.git/server/base_server/roxen.pike:5710:      void run_log_event_format (string fmt, function cb,    string facility, string action, string resource,    mapping(string:mixed) info)   {    (compiled_log_event[ fmt ] ||    compile_log_format( fmt )->log_event) (cb, facility, action,    resource, info);   }    - static LogFormat compile_log_format( string fmt ) + protected LogFormat compile_log_format( string fmt )   {    add_constant( "___LogFormat", LogFormat );       string kmd5 = md5( fmt );       object con = dbm_cached_get("local");       {    array tmp =    con->query("SELECT full,enc FROM compiled_formats WHERE md5=%s", kmd5 );
Roxen.git/server/base_server/roxen.pike:6439:   #endif /* SECURITY_PATTERN_DEBUG || HTACCESS_DEBUG */    mixed res = compile_string( code );       dbm_cached_get( "local" )    ->query("REPLACE INTO compiled_formats (md5,full,enc) VALUES (%s,%s,%s)",    kmd5,pattern,encode_value( res, master()->Encoder (res) ) );    return compile_string(code)()->f;   }       - static string cached_hostname = gethostname(); + protected string cached_hostname = gethostname();      class LogFile(string fname, string|void compressor_program)   {    Stdio.File fd;    int opened;       // FIXME: compress_logs is limited to scanning files with filename    // substitutions within a fixed directory (e.g.    // "$LOGDIR/test/Log.%y-%m-%d", not "$LOGDIR/test/%y/Log.%m-%d").    Process.Process compressor_process;    int last_compressor_scan_time; -  static void compress_logs(string fname, string active_log) +  protected void compress_logs(string fname, string active_log)    {    if(!compressor_program || !sizeof(compressor_program))    // No compressor program specified...    return;    if(compressor_process && !compressor_process->status())    // The compressor is already running...    return;    if(time(1) - last_compressor_scan_time < 300)    // Scan for compressable files at most once every 5 minutes...    return;
Roxen.git/server/base_server/roxen.pike:6540:    call_out( do_open, 900 );    }       void do_close()    {    destruct( fd );    opened = 0;    }       array(string) write_buf = ({}); -  static void do_the_write( ) +  protected void do_the_write( )    {    if( !opened ) do_open();    if( !opened ) return 0;    fd->write( write_buf );    write_buf = ({});    remove_call_out( do_close );    call_out( do_close, 10.0 );    }       int write( string what )    {    if( !sizeof( write_buf ) )    call_out( do_the_write, 1 );    write_buf += ({what});    return strlen(what);    }   }