Roxen.git / server / base_server / configuration.pike

version» Context lines:

Roxen.git/server/base_server/configuration.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2009, Roxen IS.   //      // @appears Configuration   //! A site's main configuration    - constant cvs_version = "$Id: configuration.pike,v 1.710 2010/12/02 16:11:02 mast Exp $"; + constant cvs_version = "$Id$";   #include <module.h>   #include <module_constants.h>   #include <roxen.h>   #include <request_trace.h>   #include <timers.h>      #define CATCH(P,X) do{mixed e;if(e=catch{X;})report_error("While "+P+"\n"+describe_backtrace(e));}while(0)      // Tell Pike.count_memory this is global.   constant pike_cycle_depth = 0;
Roxen.git/server/base_server/configuration.pike:208:      mapping(RequestID:mapping) connection_get( )   //! Return all currently active connections.   {    return current_connections;   }      // It's nice to have the name when the rest of __INIT executes.   string name = roxen->bootstrap_info->get();    + //! The hierarchal cache used for the HTTP protocol cache.   class DataCache   {    protected typedef array(string|mapping(string:mixed))|string|    function(string, RequestID:string|int) EntryType;       mapping(string:EntryType) cache = ([]);       int current_size;    int max_size;    int max_file_size;
Roxen.git/server/base_server/configuration.pike:231:    void flush()    {   #ifndef RAM_CACHE_NO_RELOAD_FLUSH    current_size = 0;    cache = ([]);   #endif    }       // Heuristic to calculate the entry size. Besides the data itself,    // we add the size of the key. Even though it's a shared string we -  // can pretty much assume it has no other permanent refs. 128 is a +  // can pretty much assume it has no other permanent refs. 1024 is a    // constant penalty that accounts for the keypair in the mapping and -  // that leaf entries are stored in arrays. - #define CALC_ENTRY_SIZE(key, data) (sizeof (data) + sizeof (key) + 128) +  // that leaf entries are stored in arrays and the metadata mapping. + #define CALC_ENTRY_SIZE(key, data) (sizeof (data) + sizeof (key) + 1024) + #define CALC_VARY_CB_SIZE(key) (sizeof (key) + 128)       // Expire a single entry.    protected void really_low_expire_entry(string key)    {    EntryType e = m_delete(cache, key);    if (arrayp(e)) {    current_size -= CALC_ENTRY_SIZE (key, e[0]);    if (e[1]->co_handle) {    remove_call_out(e[1]->co_handle);    } -  +  if (CacheKey cachekey = e[1]->key) { +  destruct (cachekey);    } -  +  } else if (!zero_type(e)) { +  current_size -= CALC_VARY_CB_SIZE(key);    } -  +  }       // NOTE: Avoid using this function if possible! O(n)    protected int low_expire_entry(string key_prefix)    {    if (!key_prefix) return 0;    if (arrayp(cache[key_prefix])) {    // Leaf node. No need to loop.    really_low_expire_entry(key_prefix);    return 1;    }
Roxen.git/server/base_server/configuration.pike:283:    return;    }    string url = key_prefix;    sscanf(url, "%[^\0]", url);    while(1) {    EntryType val;    if (arrayp(val = cache[key_prefix])) {    current_size -= CALC_ENTRY_SIZE (key_prefix, val[0]);    m_delete(cache, key_prefix);    return; +  } else if (!zero_type(val)) { +  current_size -= CALC_VARY_CB_SIZE(key_prefix);    }    if (!val) {    return;    }       string|array(string) key_frag;    if (stringp(val)) {    key_frag = id->request_headers[val];    } else {    key_frag = val(url, id);    }    if (key_frag)    // Avoid spoofing if key_frag happens to contain "\0\0".    key_frag = replace (key_frag, "\0", "\0\1");    else key_frag = "";    key_prefix += "\0\0" + key_frag;    }    }       //! Clear ~1/10th of the cache. -  protected void clear_some_cache() +  void clear_some_cache()    {    // FIXME: Use an iterator to avoid indices() here.    array(string) q = indices(cache);    if(!sizeof(q))    {    current_size=0;    return;    }       // The following code should be ~O(n * log(n)).    sort(q); -  for(int i = 0; i < sizeof(q)/10; i++) { +  for(int i = 0; i < sizeof(q)/10 + 1; i++) {    int r = random(sizeof(q));    string key_prefix = q[r = random(sizeof(q))];    if (!key_prefix) continue;    for(;r < sizeof(q); r++,i++) {    if (!q[r]) continue;    if (!has_prefix(q[r], key_prefix)) break;    really_low_expire_entry(q[r]);    q[r] = 0;    }    }
Roxen.git/server/base_server/configuration.pike:358:    string|function(string, RequestID: string|int) vary_cb) {    array(string|mapping(string:mixed))|string|    function(string, RequestID:string|int) old = cache[key];    if (old && (old != vary_cb)) {    SIMPLE_TRACE_ENTER (this, "Registering vary cb %O - conflicts with "    "existing entry %s, old entry expired",    vary_cb,    (arrayp (old) ? "of size " + sizeof (old[0]) :    sprintf ("%O", old)));    low_expire_entry(key); +  old = UNDEFINED; // Ensure that current size is updated below.    SIMPLE_TRACE_LEAVE ("");    }    cache[key] = vary_cb; -  +  if(!old) { +  current_size += CALC_VARY_CB_SIZE(key); +  }       SIMPLE_TRACE_ENTER (this, "Registering vary cb %O", vary_cb);       string key_frag;    if (stringp(vary_cb)) {    string|array(string) header = id->request_headers[vary_cb];    if (arrayp(header)) key_frag = header * ",";    else key_frag = header;    } else {    int|string frag = vary_cb(url, id);
Roxen.git/server/base_server/configuration.pike:386:    }       SIMPLE_TRACE_LEAVE ("Vary cb resolved to key fragment %O",    key_frag || "");       if (key_frag)    // Avoid spoofing if key_frag happens to contain "\0\0".    key_frag = replace (key_frag, "\0", "\0\1");    else key_frag = "";    key += "\0\0" + key_frag; +  entry_size += 2 + sizeof(key_frag);    }       array(string|mapping(string:mixed))|string|    function(string, RequestID:string) old = cache[key];    if (old) {    SIMPLE_TRACE_LEAVE ("Entry conflicts with existing entry %s, "    "old entry expired",    (arrayp (old) ? "of size " + sizeof (old[0]) :    sprintf ("%O", old)));    low_expire_entry(key);
Roxen.git/server/base_server/configuration.pike:597: Inside #if defined(HTTP_COMPRESSION)
  #ifdef HTTP_COMPRESSION   int(0..1) http_compr_enabled;   mapping(string:int) http_compr_main_mimes = ([]);   mapping(string:int) http_compr_exact_mimes = ([]);   int http_compr_minlen;   int http_compr_maxlen;   int(0..1) http_compr_dynamic_reqs;   Thread.Local gz_file_pool = Thread.Local();   #endif    + int handler_queue_timeout; +    // The logging format used. This will probably move to the above   // mentioned module in the future.   private mapping (int|string:string) log_format = ([]);      // A list of priority objects   array (Priority) pri = allocate_pris();      mapping modules = ([]);   //! All enabled modules in this site.   //! The format is "module":{ "copies":([ num:instance, ... ]) }
Roxen.git/server/base_server/configuration.pike:676:    }    STOP_MODULES (p->url_modules, "url module");    STOP_MODULES (p->logger_modules, "logging module");    STOP_MODULES (p->filter_modules, "filter module");    STOP_MODULES (p->location_modules, "location module");    STOP_MODULES (p->last_modules, "last module");    STOP_MODULES (p->first_modules, "first module");    STOP_MODULES (indices (p->provider_modules), "provider module");    }    -  if (mixed err = catch { -  if (object m = log_function && function_object (log_function)) { -  destruct (m); -  allmods[m] = 0; -  } -  }) report_error ("While stopping the logger: " + describe_backtrace (err)); +  end_logger();       STOP_MODULES(indices (allmods), "unclassified module");   #undef STOP_MODULES       destruct (stop_lock);   }      void stop (void|int asynch)   //! Unregisters the urls and calls stop in all modules. Uses a handler   //! thread to lessen the impact if a module hangs. Doesn't wait for
Roxen.git/server/base_server/configuration.pike:704: Inside #if defined(SNMP_AGENT)
   if (Thread.MutexKey lock = stop_all_modules_mutex->trylock()) {   #ifdef SNMP_AGENT    if(query("snmp_process") && objectp(roxen->snmpagent)) {    roxen->snmpagent->vs_stop_trap(get_config_id());    roxen->snmpagent->del_virtserv(get_config_id());    }   #endif       unregister_urls();    +  if (roxen.handler_threads_on_hold()) +  // Run do_stop_all_modules synchronously if there are no handler +  // threads running (typically during the RoxenTest_help self test). +  do_stop_all_modules (lock); +  else +  // Seems meaningless to queue this in a handler thread and then +  // just wait for it below if asynch isn't set - could just as +  // well do the work in this thread then. But now isn't a good +  // moment to mess around with it. /mast    roxen.handle (do_stop_all_modules, lock);    }       if (!asynch) stop_all_modules_mutex->lock (1);   }      string|array(string) type_from_filename( string file, int|void to,    string|void myext )   {    array(string)|string tmp;
Roxen.git/server/base_server/configuration.pike:899:    // Look for Mac OS X special filenames that are used access files in    // magic ways:    //    // foo.txt/..namedfork/data (same as foo.txt)    // foo.txt/..namedfork/rsrc (resource fork of foo.txt)    // foo.txt/rsrc (resource fork of foo.txt)    // .DS_Store (Finder info file with catalog data)    if (has_value(id->not_query, "..namedfork/") ||    has_suffix(id->not_query, "/rsrc") ||    has_value(lower_case(id->not_query), ".ds_store")) -  // Show 404 page -  return error_file(id); +  // Skip elaborate error page since we get these e.g. for WebDAV +  // mounts in OS X Finder. +  return Roxen.http_string_answer("No such file", "text/plain");    }       array a = id->not_query/"::";    // FIX: Must not subtract ":" chars since it breaks proper URL:s,    // e.g. "/internal-roxen-colorbar:x,y,z" and several others.    // id->not_query = a[0]-":";    id->not_query = a[0];    id->misc->fork_information = a[1..];    return 0;   }
Roxen.git/server/base_server/configuration.pike:1037:    RoxenModule p;    if(d=pri[i]->filter_modules)    foreach(d, p)    if(p->filter)    filter_module_cache+=({ p->filter });    }    }    return filter_module_cache;   }    -  - void init_log_file() + void end_logger()   { -  if(log_function) -  { -  // Free the old one. -  destruct(function_object(log_function)); +  if (mixed err = catch { +  if (roxen.LogFile logger = +  log_function && function_object (log_function)) { +  logger->close(); +  } +  }) report_error ("While stopping the logger: " + describe_backtrace (err));    log_function = 0;   } -  +  + void init_log_file() + { +  end_logger();    // Only try to open the log file if logging is enabled!!    if(query("Log"))    {    string logfile = query("LogFile");    if(strlen(logfile))    log_function = roxen.LogFile(logfile, query("LogFileCompressor"))->write;    }   }      private void parse_log_formats()
Roxen.git/server/base_server/configuration.pike:2732:   }      mapping error_file( RequestID id )   {    mapping res;    // Avoid recursion in 404 messages.    if (id->root_id->misc->generate_file_not_found ||    // The most popular 404 request ever? Skip the fancy error page.    id->not_query == "/favicon.ico") {    res = Roxen.http_string_answer("No such file", "text/plain"); +  res->error = 404;    } else {    id->root_id->misc->generate_file_not_found = 1; -  string data = query("ZNoSuchFile"); +  string data = "<return code='404' />" + query("ZNoSuchFile");   #if ROXEN_COMPAT <= 2.1    data = replace(data,({"$File", "$Me"}),    ({"&page.virtfile;", "&roxen.server;"}));   #endif    res = Roxen.http_rxml_answer( data, id, 0, "text/html" );    id->root_id->misc->generate_file_not_found = 0;    } -  res->error = 404; +     NOCACHE();    return res;   }      mapping auth_failed_file( RequestID id, string message )   {    // Avoid recursion in 401 messages. This could occur if the 401    // messages used files that also cause access denied.    if(id->root_id->misc->generate_auth_failed)    return Roxen.http_low_answer(401, "<title>Access Denied</title>"    "<h2 align=center>Access Denied</h2>");    id->root_id->misc->generate_auth_failed = 1;    -  string data = query("ZAuthFailed"); +  string data = "<return code='401' />" + query("ZAuthFailed");    NOCACHE();    mapping res = Roxen.http_rxml_answer( data, id, 0, "text/html" );    id->root_id->misc->generate_auth_failed = 0; -  res->error = 401; +     return res;   }      // this is not as trivial as it sounds. Consider gtext. :-)   array open_file(string fname, string mode, RequestID id, void|int internal_get,    void|int recurse_count)   {    mapping|int(0..1) file;    string oq = id->not_query;   
Roxen.git/server/base_server/configuration.pike:2783:       if (recurse_count > 50) {    TRACE_ENTER ("Looped " + recurse_count +    " times in internal redirects - giving up", 0);    TRACE_LEAVE ("");    }       else {    Configuration oc = id->conf;    id->not_query = fname; +  +  // Make sure RXML defines don't survive <insert file/>. +  // Fixes [bug 6631] where the return code for the outer +  // RXML scope caused the <insert file/> to fail. +  m_delete(id->misc, "defines"); +  m_delete(id->misc, "error_code"); +     TRY_FIRST_MODULES (file, open_file (fname, mode, id,    internal_get, recurse_count + 1));    fname = id->not_query;       if(search(mode, "R")!=-1) // raw (as in not parsed..)    {    string f;    mode -= "R";    if(f = real_file(fname, id))    {
Roxen.git/server/base_server/configuration.pike:3498:    "queueNumRuns1s",    "Number of queue runs longer than 1 second."),    SNMP.Counter(lambda() { return queue_num_runs_5s; },    "queueNumRuns5s",    "Number of queue runs longer than 5 seconds."),    SNMP.Counter(lambda() { return queue_num_runs_15s; },    "queueNumRuns15s",    "Number of queue runs longer than 15 seconds."),    }),    }) +  }), +  ({ +  UNDEFINED, +  SNMP.Counter(lambda() +  { return datacache->hits + datacache->misses; }, +  "protCacheLookups", +  "Number of protocol cache lookups."), +  SNMP.Counter(lambda() +  { return datacache->hits; }, +  "protCacheHits", +  "Number of protocol cache hits."), +  SNMP.Counter(lambda() +  { return datacache->misses; }, +  "protCacheMisses", +  "Number of protocol cache misses."), +  SNMP.Gauge(lambda() +  { return sizeof(datacache->cache); }, +  "protCacheEntries", +  "Number of protocol cache entries."), +  SNMP.Gauge(lambda() +  { return datacache->max_size/1024; }, +  "protCacheMaxSize", +  "Maximum size of protocol cache in KiB."), +  SNMP.Gauge(lambda() +  { return datacache->current_size/1024; }, +  "protCacheCurrSize", +  "Current size of protocol cache in KiB."),    })    }));    SNMP.set_owner(mib, this_object());    prot->mib->merge(mib);    }    }       if (retrieve ("EnabledModules", this)["config_filesystem#0"])    return 1; // Signal that this is the admin UI config.    return 0;
Roxen.git/server/base_server/configuration.pike:3595: Inside #if defined(MODULE_CB_DEBUG)
  #ifdef MODULE_CB_DEBUG    werror ("Calling %O->%s (%s)\n", mod, func,    map (args, lambda (mixed arg)    {return sprintf ("%O", arg);}) * ", ");   #endif    mod[func] (@args);       if (mapping(string:array(function(RoxenModule,mixed...:void))) func_cbs =    module_post_callbacks[func]) {    if (!mod_name) -  sscanf (mod->module_local_id(), "%[^#]", mod_name); +  sscanf (otomod[mod] || mod->module_local_id(), "%[^#]", mod_name);    array(function(RoxenModule,mixed...:void)) cbs;    if (array(function(RoxenModule,mixed...:void)) a = func_cbs[mod_name]) {    func_cbs[mod_name] = (a -= ({0}));    cbs = a;    }    if (array(function(RoxenModule,mixed...:void)) a = func_cbs[0]) {    func_cbs[0] = (a -= ({0}));    if (cbs) cbs += a; else cbs = a;    }    if (cbs) {
Roxen.git/server/base_server/configuration.pike:3638:    {    store("spider#0", variables, 0, this_object());    start(2);    }       store( "EnabledModules", enabled_modules, 1, this_object());    foreach(indices(modules), string modname)    {    foreach(indices(modules[modname]->copies), int i)    { -  store(modname+"#"+i, modules[modname]->copies[i]->query(), 0, this_object()); -  if (mixed err = catch(modules[modname]->copies[i]-> -  start(2, this_object(), 0))) +  RoxenModule mod = modules[modname]->copies[i]; +  store(modname+"#"+i, mod->query(), 0, this); +  if (mixed err = mod->start && catch { +  call_module_func_with_cbs (mod, "start", 2, this, 0); +  })    report_error("Error calling start in module.\n%s",    describe_backtrace (err));    }    }    invalidate_cache();   }      int save_one( RoxenModule o )   //! Save all variables in a given module.   {
Roxen.git/server/base_server/configuration.pike:3718:    }       array old_error_log = (array) old_module->error_log;       RoxenModule nm;       // Load up a new instance.    nm = mi->instance( this_object(), 0, mod_copy);    // If this is a faked module, let's call it a failure.    if (nm->module_is_disabled) -  report_notice (LOC_C(0, "Module is disabled") + "\n"); +  report_notice (LOC_C(1047, "Module is disabled") + "\n");    else if( nm->not_a_module )    {    old_module->report_error(LOC_C(385,"Reload failed")+"\n");    RXML.set_context (old_ctx);    return old_module;    }       disable_module( modname, nm );    destruct( old_module );   
Roxen.git/server/base_server/configuration.pike:3960: Inside #if defined(MODULE_LEVEL_SECURITY)
   me->defvar("_seclvl", 0, DLOCALE(18, "Security: Security level"),    TYPE_INT,    DLOCALE(305, "The modules security level is used to determine if a "    " request should be handled by the module."    "\n<p><h2>Security level vs Trust level</h2>"    " Each module has a configurable <i>security level</i>."    " Each request has an assigned trust level. Higher"    " <i>trust levels</i> grants access to modules with higher"    " <i>security levels</i>."    "\n<p><h2>Definitions</h2><ul>" -  " <li>A requests initial Trust level is infinitely high.</li>" +  " <li>A requests initial trust level is infinitely high.</li>"    " <li> A request will only be handled by a module if its"    " <i>trust level</i> is higher or equal to the"    " <i>security level</i> of the module.</li>"    " <li> Each time the request is handled by a module the" -  " <i>trust level</i> of the module will be set to the" +  " <i>trust level</i> of the request will be set to the"    " lower of its <i>trust level</i> and the modules"    " <i>security level</i>, <i>unless</i> the security "    " level of the module is 0, which is a special "    " case and means that no change should be made.</li>"    " </ul></p>"    "\n<p><h2>Example</h2>"    " Modules:<ul>"    " <li> User filesystem, <i>security level</i> 1</li>"    " <li> Filesystem module, <i>security level</i> 3</li>"    " <li> CGI module, <i>security level</i> 2</li>"    " </ul></p>"    "\n<p>A request handled by \"User filesystem\" is assigned"    " a <i>trust level</i> of one after the <i>security"    " level</i> of that module. That request can then not be"    " handled by the \"CGI module\" since that module has a"    " higher <i>security level</i> than the requests trust"    " level.</p>"    "\n<p>On the other hand, a request handled by the the" -  " \"Filsystem module\" could later be handled by the" +  " \"Filesystem module\" could later be handled by the"    " \"CGI module\".</p>"));       } else {    me->definvisvar("_seclvl", -10, TYPE_INT); /* A very low one */    }    }   #endif    } else {    me->defvar("_priority", 0, "", TYPE_INT, "", 0, 1);    }
Roxen.git/server/base_server/configuration.pike:4011:    module_set_counter++;       // Below we may have recursive calls to this function. They may    // occur already in setvars due to e.g. automatic dependencies in    // Variable.ModuleChoice.       mapping(string:mixed) stored_vars = retrieve(modname + "#" + id, this_object());    int has_stored_vars = sizeof (stored_vars); // A little ugly, but it suffices.    me->setvars(stored_vars);    +  if (me->not_a_module) nostart = 1; +     if(!nostart) call_start_callbacks( me, moduleinfo, module );      #ifdef MODULE_DEBUG    if (enable_module_batch_msgs) {    if(moduleinfo->config_locked[this_object()])    report_debug("\bLocked %6.1fms\n", (gethrtime()-start_time)/1000.0);    else if (me->not_a_module)    report_debug("\bN/A %6.1fms\n", (gethrtime()-start_time)/1000.0);    else    report_debug("\bOK %6.1fms\n", (gethrtime()-start_time)/1000.0);
Roxen.git/server/base_server/configuration.pike:4665:   a server configuration is created, this variable is set to the current   version. After that it's never changed automatically, thereby ensuring   that server configurations migrated from earlier Roxen versions is   kept at the right compatibility level.</p>      <p>This variable may be changed manually, but it's advisable to test   the site carefully afterwards. A reload of the whole server   configuration is required to propagate the change properly to all   modules.</p>    - <p>Available compatibility levels: - <table> - <tr valign='top'><td>2.1&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen WebServer 2.1.</td></tr> - <tr valign='top'><td>2.2&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen WebServer 2.2.</td></tr> - <tr valign='top'><td>2.4&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen WebServer 2.4. This version is also -  commonly known as 3.2 - the version number that applies to the -  release of Roxen CMS which contains Roxen WebServer 2.4.</td></tr> - <tr valign='top'><td>2.5&nbsp;&nbsp;</td> -  <td>Corresponds to no released version. This compatibility level is -  only used to turn on some optimizations that have compatibility + <p>Compatibility level notes:</p> +  + <ul> +  <li>2.4 also applies to the version commonly known as 3.2. That was +  the release of Roxen CMS which contained Roxen WebServer 2.4.</li> +  +  <li>2.5 corresponds to no released version. This compatibility level +  is only used to turn on some optimizations that have compatibility    issues with 2.4, notably the optimization of cache static tags in -  the &lt;cache&gt; tag.</td></tr> - <tr valign='top'><td>3.3&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen 3.3.</td></tr> - <tr valign='top'><td>3.4&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen 3.4.</td></tr> - <tr valign='top'><td>4.0&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen 4.0.</td></tr> - <tr valign='top'><td>4.5&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen 4.5.</td></tr> - <tr valign='top'><td>5.0&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen 5.0.</td></tr> - <tr valign='top'><td>5.1&nbsp;&nbsp;</td> -  <td>Corresponds to Roxen 5.1.</td></tr> - </table></p>"))); +  the &lt;cache&gt; tag.</li>    -  +  <li>There are no compatibility differences between 5.0 and 5.1, so +  those two compatibility levels can be used interchangeably.</li> + </ul>"))); +     set ("compat_level", roxen.roxen_ver);    // Note to developers: This setting can be accessed through    // id->conf->query("compat_level") or similar, but observe that that    // call is not entirely cheap. It's therefore advisable to put it in    // a local variable if the compatibility level is to be tested    // frequently. It's perfectly all right to do that in e.g. the    // module start function, since the documentation explicitly states    // that a reload of all modules is necessary to propagate a change    // of the setting.   
Roxen.git/server/base_server/configuration.pike:4796:   for all kinds of messages. If an unknown or inapplicable specifier is   encountered it typically expands to '<code>-</code>', but in some   cases it expands to a dummy value that is syntactically compatible   with what it usually expands to.</p>      <p>For compatibility, underscores ('_') may be used wherever   hyphens ('-') occur in the specifier names.</p>      <h3>Format specifiers for both access and event logging</h3>    - <table><tbody valign='top'> + <table class='hilite-1stcol'><tbody valign='top'>   <tr><td>\\n \\t \\r</td>    <td>Insert a newline, tab or linefeed character, respectively.</td></tr>   <tr><td>$char(int)</td>    <td>Insert the (1 byte) character specified by the integer. E.g.    '<code>$char(36)</code>' inserts a literal '<code>$</code>'    character.</td></tr>   <tr><td>$wchar(int)</td>    <td>Insert the specified integer using 2 bytes in network byte    order. Specify a negative integer to get the opposite (i.e. big    endian) order.</td></tr>
Roxen.git/server/base_server/configuration.pike:4844:   <tr><td>$server-cputime</td>    <td>Server cpu (user+system) time in milliseconds.</td></tr>   <tr><td>$server-usertime</td>    <td>Server cpu user time in milliseconds.</td></tr>   <tr><td>$server-systime</td>    <td>Server cpu system time in milliseconds.</td></tr>   </tbody></table>      <h3>Format specifiers for access logging</h3>    - <table><tbody valign='top'> + <table class='hilite-1stcol'><tbody valign='top'>   <tr><td>$host</td>    <td>The remote host name, or ip number.</td></tr>   <tr><td>$vhost</td>    <td>The Host request-header sent by the client, or '-' if none.</td></tr>   <tr><td>$ip-number</td>    <td>The remote ip number.</td></tr>   <tr><td>$bin-ip-number</td>    <td>The remote host ip as a binary integer number.</td></tr>   <tr><td>$xff</td>    <td>The remote host name/ip taken from the X-Forwarded-For header, or    '-' if none is provided. If multiple headers or multiple values are    given the first value is logged; this should correspond to the    originating computer.</td></tr>   <tr><td>$method</td>    <td>Request method.</td></tr>   <tr><td>$full-resource</td>    <td>Full requested resource, including any query fields.</td></tr>   <tr><td>$protocol</td>    <td>The protocol used (normally HTTP/1.1).</td></tr> -  + <tr><td>$scheme</td> +  <td>The URL scheme (e.g. http or https) derived from the port handler +  module.</td></tr>   <tr><td>$response</td>    <td>The response code sent.</td></tr>   <tr><td>$bin-response</td>    <td>The response code sent as a binary short number.</td></tr>   <tr><td>$length</td>    <td>The length of the data section of the reply.</td></tr>   <tr><td>$bin-length</td>    <td>Same, but as a 32 bit integer in network byte order.</td></tr>   <tr><td>$queue-length</td>    <td>Number of jobs waiting to be processed by the handler threads
Roxen.git/server/base_server/configuration.pike:4927:    otherwise '0'.</td></tr>   <tr><td>$content-type</td>    <td>Resource MIME type.</td></tr>   <tr><td>$cookies</td>    <td>All cookies sent by the browser, separated by ';'.</td></tr>      <tr><td>$cache-status</td>    <td>A comma separated list of words (containing no whitespace)    that describes how the request got handled by various caches:    -  <table><tbody valign='top'> +  <table class='hilite-1stcol'><tbody valign='top'>    <tr><td>protcache</td>    <td>The page is served from the HTTP protocol cache.</td></tr>    <tr><td>protstore</td>    <td>The page is stored in the HTTP protocol cache.</td></tr>    <tr><td>stale</td>    <td>There is a stale entry in the HTTP protocol cache. A    refresh is underway in the background and the stale entry is    sent in the meantime to avoid a long response time and server    congestion.</td></tr>    <tr><td>refresh</td>    <td>This is the finishing of the background refresh request    for the entry in the HTTP protocol cache.</td></tr> -  +  <tr><td>icachedraw</td> +  <td>A server-generated image had to be rendered from scratch.</td></tr> +  <tr><td>icacheram</td> +  <td>A server-generated image was found in the RAM cache.</td></tr> +  <tr><td>icachedisk</td> +  <td>A server-generated image was found in the disk cache (i.e. in +  the server's MySQL database).</td></tr>    <tr><td>pcoderam</td>    <td>A hit in the RXML p-code RAM cache.</td></tr>    <tr><td>pcodedisk</td>    <td>A hit in the RXML p-code persistent cache.</td></tr> -  +  <tr><td>pcodestore</td> +  <td>P-code is added to or updated in the persistent cache.</td></tr> +  <tr><td>pcodestorefailed</td> +  <td>An attempt to add or update p-code in the persistent cache +  failed (e.g. due to a race with another request).</td></tr>    <tr><td>cachetag</td>    <td>RXML was evaluated without any cache miss in any RXML    &lt;cache&gt; tag. The &lt;nocache&gt; tag does not count as a    miss.</td></tr>    <tr><td>xsltcache</td>    <td>There is a hit XSLT cache.</td></tr>    <tr><td>nocache</td>    <td>No hit in any known cache, and not added to the HTTP    protocol cache.</td></tr>    </tbody></table></td></tr>      <tr><td>$eval-status</td>    <td>A comma separated list of words (containing no whitespace)    that describes how the page has been evaluated:    -  <table><tbody valign='top'> +  <table class='hilite-1stcol'><tbody valign='top'>    <tr><td>xslt</td>    <td>XSL transform.</td></tr>    <tr><td>rxmlsrc</td>    <td>RXML evaluated from source.</td></tr>    <tr><td>rxmlpcode</td>    <td>RXML evaluated from compiled p-code.</td></tr>    </tbody></table></td></tr>      <tr><td>$protcache-cost</td>    <td>The lookup depth in the HTTP protocol module low-level cache.</td></tr>   </tbody></table>      <h3>Event logging</h3>      <p>The known event logging facilities and modules are described   below.</p>    - <dl>" - #ifdef NEW_RAM_CACHE -  #"\n + <dl>   <dt>Facility: roxen</dt>    <dd><p>This is logging for systems in the Roxen WebServer core.    For logging that is not related to any specific configuration, the    configuration for the Administration Interface is used.</p>       <p>The known events are:</p>    -  <table><tbody valign='top'> +  <table class='hilite-1stcol'><tbody valign='top'>    <tr><td>ram-cache-gc</td>    <td>Logged after the RAM cache GC has run. $handle-time and    $handle-cputime are set to the time the GC took (see    descriptions above for details).</td></tr>    <tr><td>ram-cache-rebase</td>    <td>Logged when the RAM cache has performed a rebias of the    priority queue values. Is a problem only if it starts to    happen too often.</td></tr> -  </tbody></table></dd>" - #endif -  #"\n +  </tbody></table></dd> +    <dt>Facility: sbfs</dt>    <dd><p>A SiteBuilder file system.</p>       <p>The actions <code>commit</code>, <code>purge</code>,    <code>mkdir</code>, <code>set-dir-md</code>, and    <code>rmdir</code> are logged for file system changes except those    in edit areas.</p>       <p>The action <code>crawl-file</code> is logged for files that are    crawled by the persistent cache crawler.</p>       <p>The actions <code>file-change</code> and    <code>dir-change-flat</code> are logged when external file and    directory changes are detected (and this feature is enabled).</p>       <p>These extra format specifiers are defined where applicable:</p>    -  <table><tbody valign='top'> +  <table class='hilite-1stcol'><tbody valign='top'>    <tr><td>$ac-userid</td>    <td>The ID number of the AC identity whose edit area was used.    Zero for the common view area.</td></tr>    <tr><td>$workarea</td>    <td>The unique tag for the work area. Empty for the main work    area.</td></tr>    <tr><td>$commit-type</td>    <td>The type of file commit, one of <code>create</code>,    <code>edit</code>, <code>delete</code>, and    <code>undelete</code>.</td></tr>
Roxen.git/server/base_server/configuration.pike:5049:   </dl>"), 0, lambda(){ return !query("Log");});       // Make the widget above a bit larger.    getvar ("LogFormat")->rows = 20;    getvar ("LogFormat")->cols = 80;       // FIXME: Mention it is relative to getcwd(). Can not be localized in pike 7.0.    defvar("LogFile", "$LOGDIR/"+Roxen.short_name(name)+"/Log",    DLOCALE(30, "Logging: Log file"), TYPE_FILE,    DLOCALE(31, "The log file. " -  "" +     "A file name. Some substitutions will be done:"    "<pre>"    "%y Year (e.g. '1997')\n"    "%m Month (e.g. '08')\n"    "%d Date (e.g. '10' for the tenth)\n"    "%h Hour (e.g. '00')\n"    "%H Hostname\n"    "</pre>")    ,0, lambda(){ return !query("Log");});   
Roxen.git/server/base_server/configuration.pike:5261:    http_compr_exact_mimes = mkmapping(exact_mimes,    ({ 1 }) * sizeof(exact_mimes));    http_compr_main_mimes = mkmapping(main_mimes,    ({ 1 }) * sizeof(main_mimes));    };    defvar("http_compression_mimetypes",    ({ "text/*",    "application/javascript",    "application/x-javascript",    "application/json", -  "application/xhtml+xml" }), +  "application/xhtml+xml", +  "image/svg+xml" }),    DLOCALE(1002, "Compression: Enabled MIME-types"),    TYPE_STRING_LIST,    DLOCALE(1003, "The MIME types for which to enable compression. The "    "forms \"maintype/*\" and \"maintype/subtype\" are allowed, "    "but globbing on the general form (such as " -  "\"maintype/*subtype\") is not allowed and such globs will " -  "be silently ignored.")) +  "\"maintype/*subtype\" or \"maintype/sub*\") is not allowed " +  "and such globs will be silently ignored."))    ->add_changed_callback(lambda(object v)    { set_mimetypes(v->query());    });    set_mimetypes(query("http_compression_mimetypes"));       defvar("http_compression_min_size", 1024,    DLOCALE(1004, "Compression: Minimum content size"),    TYPE_INT,    DLOCALE(1005, "The minimum file size for which to enable compression. "    "(It might not be worth it to compress a request if it can "
Roxen.git/server/base_server/configuration.pike:5563:    <td></td>    </tr>   </table>      </body>   </html>",    DLOCALE(413, "Authentication failed message"),    TYPE_TEXT_FIELD|VAR_PUBLIC,    DLOCALE(420, "What to return when an authentication attempt failed."));    +  if (!retrieve ("EnabledModules", this)["config_filesystem#0"]) { +  // Do not use a handler queue timeout of the administration +  // interface. You most probably don't want to get a 503 in your +  // face when you're trying to reconfigure an overloaded server... +  defvar("503-message", #"<html> + <head> +  <title>503 - Server Too Busy</title> +  <style> +  .header { font-family: arial; +  font-size: 20px; +  line-height: 160% } +  .msg { font-family: verdana, helvetica, arial, sans-serif; +  font-size: 12px; +  line-height: 160% } +  .url { font-family: georgia, times, serif; +  font-size: 18px; +  padding-top: 6px; +  padding-bottom: 20px } +  .info { font-family: verdana, helvetica, arial, sans-serif; +  font-size: 10px; +  color: #999999 } +  </style> + </head> + <body bgcolor='#f2f1eb' vlink='#2331d1' alink='#f6f6ff' +  leftmargin='50' rightmargin='0' topmargin='50' bottommargin='0' +  style='margin: 0; padding: 0'>    -  + <table border='0' cellspacing='0' cellpadding='0' height='99%'> +  <colgroup> +  <col span='3' /> +  <col width='356' /> +  <col width='0*' /> +  </colgroup> +  <tr><td height='50'></td></tr> +  <tr> +  <td width='100'></td> +  <td> +  <div class='header'>503 &mdash; Server Too Busy</div> +  </td> +  </tr> +  <tr> +  <td></td> +  <td> +  <div class='msg'>Unable to retrieve</div> +  <div class='url'>&page.virtfile;</div> +  </td> +  </tr> +  <tr> +  <td></td> +  <td> +  <div class='msg'> +  The server is currently too busy to serve your request. Please try again in a few moments. +  </div> +  </td> +  <td>&nbsp;</td> +  </tr> +  <tr valign='bottom' height='100%'> +  <td></td> +  <td> +  <table border='0' cellspacing='0' cellpadding='0'> +  <tr> +  <td class='info'> +  &nbsp;&nbsp;<b>&roxen.product-name;</b> <font color='#ffbe00'>|</font> +  version &roxen.dist-version; +  </td> +  </tr> +  </table> +  </td> +  <td></td> +  </tr> + </table>    -  + </body> + </html>", +  DLOCALE(1048, "Server too busy message"), +  TYPE_TEXT_FIELD|VAR_PUBLIC, +  DLOCALE(1049, "What to return if the server is too busy. See also " +  "\"Handler queue timeout\".")); +  +  defvar("handler_queue_timeout", 30, +  DLOCALE(1050, "Handler queue timeout"), +  TYPE_INT, +  DLOCALE(1051, #"Requests that have been waiting this many seconds on + the handler queue will not be processed. Instead, a 503 error code and the + \"Server too busy message\" will be returned to the client. This may help the + server to cut down the queue length after spikes of heavy load.")) +  ->add_changed_callback(lambda(object v) +  { handler_queue_timeout = v->query(); }); +  handler_queue_timeout = query("handler_queue_timeout"); +  } +    #ifdef SNMP_AGENT    // SNMP stuffs    defvar("snmp_process", 0,    "SNMP: Enabled",TYPE_FLAG,    "If set, per-server objects will be added to the SNMP agent database.",    0, snmp_global_disabled);    defvar("snmp_community", "public:ro",    "SNMP: Community string", TYPE_STRING,    "The community string and access level for manipulation on server "    " specific objects.",