835c6c2001-06-17Martin Nilsson // This file is part of Roxen WebServer. // Copyright © 1996 - 2001, Roxen IS. //
6b67fe2001-08-24Martin Nilsson // @appears Configuration //! A site's main configuration
ca9c4f2004-06-21Jonas Wallden constant cvs_version = "$Id: configuration.pike,v 1.581 2004/06/21 08:11:11 jonasw Exp $";
b1fca01996-11-12Per Hedbor #include <module.h>
a59d252000-07-04Per Hedbor #include <module_constants.h>
14179b1997-01-29Per Hedbor #include <roxen.h>
c5e0961999-10-04Per Hedbor #include <request_trace.h>
9c19002001-02-27Per Hedbor #include <timers.h>
8afc811998-02-04Per Hedbor 
c7a5f01999-02-16Per Hedbor #define CATCH(P,X) do{mixed e;if(e=catch{X;})report_error("While "+P+"\n"+describe_backtrace(e));}while(0)
18be211998-05-07Henrik Grubbström (Grubba) 
23414a2000-07-21Andreas Lange // --- Locale defines --- //<locale-token project="roxen_start"> LOC_S </locale-token> //<locale-token project="roxen_config"> LOC_C </locale-token> //<locale-token project="roxen_message"> LOC_M </locale-token> //<locale-token project="roxen_config"> DLOCALE </locale-token> #define LOC_S(X,Y) _STR_LOCALE("roxen_start",X,Y) #define LOC_C(X,Y) _STR_LOCALE("roxen_config",X,Y) #define LOC_M(X,Y) _STR_LOCALE("roxen_message",X,Y) #define DLOCALE(X,Y) _DEF_LOCALE("roxen_config",X,Y)
18be211998-05-07Henrik Grubbström (Grubba) 
199d031999-09-05Francesco Chemolli #ifdef THROTTLING_DEBUG #undef THROTTLING_DEBUG
91d3c32001-03-12Martin Nilsson #define THROTTLING_DEBUG(X) report_debug("Throttling: "+X+"\n")
199d031999-09-05Francesco Chemolli #else #define THROTTLING_DEBUG(X) #endif
10c7e11999-12-28Martin Nilsson #ifdef REQUEST_DEBUG
91d3c32001-03-12Martin Nilsson # define REQUEST_WERR(X) report_debug("CONFIG: "+X+"\n")
10c7e11999-12-28Martin Nilsson #else # define REQUEST_WERR(X) #endif
4717052001-05-07Per Hedbor  #ifdef AVERAGE_PROFILING
7e16102001-11-01Henrik Grubbström (Grubba)  #if !constant(gethrvtime) #define gethrvtime() gethrtime() #endif /* !constant(gethrvtime) */
4717052001-05-07Per Hedbor class ProfStack { array current_stack = ({}); void enter( string k, RequestID id ) { current_stack += ({ ({ k, gethrtime(), gethrvtime() }) }); } void leave( string k, RequestID id ) { int t0 = gethrtime(); int t1 = gethrvtime(); if( !sizeof(current_stack ) ) {
7937df2001-05-16Per Hedbor // report_error("Popping out of profiling stack\n");
4717052001-05-07Per Hedbor  return; } int i = sizeof( current_stack )-1; while( current_stack[ i ][0] != k && i >= 0 ) i--; if(i < 0 ) { return; }
7937df2001-05-16Per Hedbor  void low_leave( int i ) { int tt = t0-current_stack[i][1]; int ttv = t1-current_stack[i][2]; if( i > 0 ) // Do not count child time in parent. { current_stack[i-1][1]+=tt+gethrtime()-t0; current_stack[i-1][2]+=ttv+gethrvtime()-t1; } current_stack = current_stack[..i-1]; add_prof_entry( id, k, tt, ttv ); };
4717052001-05-07Per Hedbor 
7937df2001-05-16Per Hedbor  if( i != sizeof( current_stack )-1 )
4717052001-05-07Per Hedbor  {
7937df2001-05-16Per Hedbor  for( int j = sizeof( current_stack )-1; j>=i; j-- ) low_leave( j ); return;
4717052001-05-07Per Hedbor  }
7937df2001-05-16Per Hedbor  low_leave( i );
4717052001-05-07Per Hedbor  } } class ProfInfo( string url ) { mapping data = ([]); void add( string k, int h, int hrv ) { if( !data[k] ) data[k] = ({ h, hrv, 1 }); else { data[k][0]+=h; data[k][1]+=hrv; data[k][2]++; } } array summarize_table( ) { array table = ({}); int n, t, v; foreach( indices( data ), string k ) table += ({ ({ k, sprintf( "%d", (n=data[k][2]) ), sprintf("%5.2f",(t=data[k][0])/1000000.0), sprintf("%5.2f", (v=data[k][1])/1000000.0), sprintf("%8.2f", t/n/1000.0), sprintf("%8.2f",v/n/1000.0), }) }); sort( (array(float))column(table,2), table ); return reverse(table); } void dump( ) { write( "\n"+url+": \n" );
ab1e022002-03-06Henrik Grubbström (Grubba)  ADT.Table.table t = ADT.Table.table( summarize_table(), ({ "What", "Calls", "Time", "CPU", "t/call(ms)", "cpu/call(ms)" }));
4717052001-05-07Per Hedbor  write( ADT.Table.ASCII.encode( t )+"\n" ); } } mapping profiling_info = ([]); void debug_write_prof( ) { foreach( sort( indices( profiling_info ) ), string p ) profiling_info[p]->dump(); } void add_prof_entry( RequestID id, string k, int hr, int hrv ) {
e8dffa2001-05-14Per Hedbor  string l = id->not_query;
7937df2001-05-16Per Hedbor // if( has_prefix( k, "find_internal" ) ) l = dirname(l); if( has_prefix( l, query_internal_location() ) ) l = dirname( l ); // enough, really. if( !profiling_info[l] ) profiling_info[l] = ProfInfo(l);
e8dffa2001-05-14Per Hedbor  profiling_info[l]->add( k, hr, hrv );
4717052001-05-07Per Hedbor } void avg_prof_enter( string name, string type, RequestID id ) { if( !id->misc->prof_stack ) id->misc->prof_stack = ProfStack(); id->misc->prof_stack->enter( name+":"+type,id ); } void avg_prof_leave( string name, string type, RequestID id ) { if( !id->misc->prof_stack ) id->misc->prof_stack = ProfStack(); id->misc->prof_stack->leave( name+":"+type,id ); } #endif
b1fca01996-11-12Per Hedbor /* A configuration.. */
9a8a152000-09-25Per Hedbor inherit Configuration; inherit "basic_defvar";
dfe0362000-03-19Martin Nilsson 
b9c3872002-03-27Per Hedbor static mapping(RequestID:mapping) current_connections = set_weak_flag( ([ ]), 1 ); void connection_add( RequestID id, mapping data ) //! Add a connection. The data mapping can contain things such as //! currently sent bytes. //! //! See protocols/http.pike and slowpipe.pike for more information. //! //! You are not in any way forced to use this method from your //! protocol module. The information is only used for debug purposes //! in the configuration interface. //! //! You have to keep a reference to the mapping on your own, none is //! kept by the configuration object. { current_connections[id] = data; } mapping connection_drop( RequestID id ) //! Remove a connection from the list of currently active connections. //! Returns the mapping previously added with connection_add, if any. { m_delete( current_connections, id ); } mapping(RequestID:mapping) connection_get( ) //! Return all currently active connections. { return current_connections; }
3557f52001-06-30Martin Stjernholm // It's nice to have the name when the rest of __INIT executes. string name = roxen->bootstrap_info->get();
d093992000-09-25Per Hedbor // Trivial cache (actually, it's more or less identical to the 200+ // lines of C in HTTPLoop. But it does not have to bother with the // fact that more than one thread can be active in it at once. Also, // it does not have to delay free until all current connections using // the cache entry is done...) class DataCache { mapping(string:array(string|mapping(string:mixed))) cache = ([]); int current_size; int max_size; int max_file_size; int hits, misses; void flush() { current_size = 0; cache = ([]); } static void clear_some_cache() { array q = indices( cache ); if(!sizeof(q)) { current_size=0; return; } for( int i = 0; i<sizeof( q )/10; i++ ) expire_entry( q[random(sizeof(q))] ); } void expire_entry( string url ) { if( cache[ url ] ) { current_size -= strlen(cache[url][0]); m_delete( cache, url ); } } void set( string url, string data, mapping meta, int expire ) {
c42ab32002-04-15Jonas Wallden  if( strlen( data ) > max_file_size ) return;
d093992000-09-25Per Hedbor  call_out( expire_entry, expire, url ); current_size += strlen( data ); cache[url] = ({ data, meta }); int n; while( (current_size > max_size) && (n++<10)) clear_some_cache(); } array(string|mapping(string:mixed)) get( string url ) { mixed res; if( res = cache[ url ] ) hits++; else misses++; return res; } void init_from_variables( ) { max_size = query( "data_cache_size" ) * 1024; max_file_size = query( "data_cache_file_max_size" ) * 1024; if( max_size < max_file_size ) max_size += max_file_size; int n; while( (current_size > max_size) && (n++<10)) clear_some_cache(); } static void create() { init_from_variables(); } }
3b17831998-11-22Per Hedbor #include "rxml.pike";
9a8a152000-09-25Per Hedbor constant store = roxen.store; constant retrieve = roxen.retrieve; constant remove = roxen.remove;
14179b1997-01-29Per Hedbor 
65c6d22000-03-10Martin Nilsson int config_id;
9a8a152000-09-25Per Hedbor int get_config_id() {
65c6d22000-03-10Martin Nilsson  if(config_id) return config_id; for(int i=sizeof(roxen->configurations); i;) if(roxen->configurations[--i]->name==name) return config_id=i; }
c7a5f01999-02-16Per Hedbor string get_doc_for( string region, string variable ) {
e351dd1999-11-29Per Hedbor  RoxenModule module;
c7a5f01999-02-16Per Hedbor  if(variable[0] == '_') return 0; if((int)reverse(region)) return 0; if(module = find_module( region )) { if(module->variables[variable])
b2c49b2000-07-09Per Hedbor  return module->variables[variable]->name()+ "\n"+module->variables[ variable ]->doc();
c7a5f01999-02-16Per Hedbor  } if(variables[ variable ])
b2c49b2000-07-09Per Hedbor  return variables[variable]->name()+ "\n"+variables[ variable ]->doc();
c7a5f01999-02-16Per Hedbor }
14179b1997-01-29Per Hedbor 
e351dd1999-11-29Per Hedbor string query_internal_location(RoxenModule|void mod)
5839c31999-01-22Marcus Comstedt {
9ac0332002-11-05Anders Johansson  return internal_location+(mod?replace(otomod[mod]||"", "#", "!")+"/":"");
5839c31999-01-22Marcus Comstedt }
b1fca01996-11-12Per Hedbor  string query_name() {
8552d92001-01-13Martin Nilsson  if(strlen(query("name"))) return query("name");
b1fca01996-11-12Per Hedbor  return name; } string comment() {
8552d92001-01-13Martin Nilsson  return query("comment");
b1fca01996-11-12Per Hedbor }
b6675b2002-10-28Martin Stjernholm private float cached_compat_level; float compat_level() { if (cached_compat_level == 0.0) cached_compat_level = (float) query ("compat_level"); return cached_compat_level; }
b1fca01996-11-12Per Hedbor /* A 'pri' is one of the ten priority objects. Each one holds a list * of modules for that priority. They are all merged into one list for * performance reasons later on. */
e351dd1999-11-29Per Hedbor array (Priority) allocate_pris()
b1fca01996-11-12Per Hedbor {
c5e0961999-10-04Per Hedbor  return allocate(10, Priority)();
b1fca01996-11-12Per Hedbor }
9ac0332002-11-05Anders Johansson // Cache some configuration variables. private int sub_req_limit = 30; private string internal_location = "/_internal/";
2f1e892000-08-15Martin Nilsson // The logging format used. This will probably move to the above
b1fca01996-11-12Per Hedbor // mentioned module in the future.
7a243b2000-08-19Per Hedbor private mapping (int:string) log_format = ([]);
b1fca01996-11-12Per Hedbor 
c5e0961999-10-04Per Hedbor // A list of priority objects
053a552000-10-04Per Hedbor array (Priority) pri = allocate_pris();
b1fca01996-11-12Per Hedbor 
9c19002001-02-27Per Hedbor mapping modules = ([]);
1dd64a2000-09-19Mattias Wingstedt //! All enabled modules in this site.
e75fd12000-07-26Johan Sundström //! The format is "module":{ "copies":([ num:instance, ... ]) }
b1fca01996-11-12Per Hedbor 
9c19002001-02-27Per Hedbor mapping (RoxenModule:string) otomod = ([]);
e75fd12000-07-26Johan Sundström //! A mapping from the module objects to module names
b1fca01996-11-12Per Hedbor  // Caches to speed up the handling of the module search. // They are all sorted in priority order, and created by the functions // below. private array (function) url_module_cache, last_module_cache; private array (function) logger_module_cache, first_module_cache; private array (function) filter_module_cache; private array (array (string|function)) location_module_cache; private mapping (string:array (function)) file_extension_module_cache=([]);
e351dd1999-11-29Per Hedbor private mapping (string:array (RoxenModule)) provider_module_cache=([]);
3342dd2001-01-19Per Hedbor private array (RoxenModule) auth_module_cache, userdb_module_cache;
b1fca01996-11-12Per Hedbor 
38dca81996-12-10Per Hedbor 
0e15572001-02-23Martin Stjernholm void unregister_urls()
38dca81996-12-10Per Hedbor {
9c3c6c2001-11-09Henrik Grubbström (Grubba)  foreach( registered_urls + failed_urls, string url ) roxen.unregister_url(url, this_object());
dffa222000-12-10Per Hedbor  registered_urls = ({});
38dca81996-12-10Per Hedbor }
0e15572001-02-23Martin Stjernholm private int num_modules = 0; #ifdef THREADS private Thread.Condition modules_stopped = Thread.Condition();
7660ad2002-10-23Martin Stjernholm private Thread.Mutex modules_stopped_mutex = Thread.Mutex();
0e15572001-02-23Martin Stjernholm #endif private void safe_stop_module (RoxenModule mod, string desc) { if (mixed err = catch (mod && mod->stop && mod->stop())) report_error ("While stopping " + desc + ": " + describe_backtrace (err));
a5249e2001-03-05Per Hedbor #ifdef THREADS
7660ad2002-10-23Martin Stjernholm  Thread.MutexKey lock = modules_stopped_mutex->lock(); if (!--num_modules) modules_stopped->signal(); lock = 0; #else --num_modules;
a5249e2001-03-05Per Hedbor #endif
0e15572001-02-23Martin Stjernholm } void stop (void|int asynch) //! Unregisters the urls and calls stop in all modules. Uses the //! handler threads to lessen the impact if a module hangs. Doesn't //! wait for all modules to finish if @[asynch] is nonzero. {
79b7c32001-09-13Honza Petrous  #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
0e15572001-02-23Martin Stjernholm  unregister_urls(); multiset allmods = mkmultiset (indices (otomod)); num_modules = 17; if (types_module) { num_modules++; roxen.handle (safe_stop_module, types_module, "type module"); allmods[types_module] = 0; } if (dir_module) { num_modules++; roxen.handle (safe_stop_module, dir_module, "directory module"); allmods[dir_module] = 0; } for(int i=0; i<10; i++) if (Priority p = pri[i]) { #define STOP_MODULES(MODS, DESC) \ foreach(MODS, RoxenModule m) \ if (allmods[m]) { \ num_modules++; \ roxen.handle (safe_stop_module, m, DESC); \ allmods[m] = 0; \ } 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)); STOP_MODULES(indices (allmods), "unclassified module"); #undef STOP_MODULES if (!asynch) { #ifdef THREADS
7660ad2002-10-23Martin Stjernholm  Thread.MutexKey lock = modules_stopped_mutex->lock(); num_modules -= 17; if (num_modules) modules_stopped->wait (lock); lock = 0;
0e15572001-02-23Martin Stjernholm #else
7660ad2002-10-23Martin Stjernholm  if (num_modules != 17)
0e15572001-02-23Martin Stjernholm  error ("num_modules shouldn't be nonzero here when running nonthreaded.\n"); #endif } }
d449d52003-06-02Henrik Grubbström (Grubba) string|array(string) type_from_filename( string file, int|void to, string|void myext )
b1fca01996-11-12Per Hedbor {
f28c112000-03-06Martin Nilsson  array(string)|string tmp;
14179b1997-01-29Per Hedbor  if(!types_fun) return to?({ "application/octet-stream", 0 }):"application/octet-stream";
0ba0382001-08-28Henrik Grubbström (Grubba)  string ext = lower_case(myext || Roxen.extension(file));
41b77c1999-07-15David Hedbor 
14179b1997-01-29Per Hedbor  if(tmp = types_fun(ext)) { mixed tmp2,nx;
0ba0382001-08-28Henrik Grubbström (Grubba)  // FIXME: Ought to support several levels of "strip". if (tmp[0] == "strip")
14179b1997-01-29Per Hedbor  { tmp2=file/".";
0ba0382001-08-28Henrik Grubbström (Grubba)  if (sizeof(tmp2) > 2)
14179b1997-01-29Per Hedbor  nx=tmp2[-2];
0ba0382001-08-28Henrik Grubbström (Grubba)  if (nx && (tmp2 = types_fun(nx)))
14179b1997-01-29Per Hedbor  tmp[0] = tmp2[0];
0ba0382001-08-28Henrik Grubbström (Grubba)  else if (tmp2 = types_fun("default"))
9be5aa1998-07-03Henrik Grubbström (Grubba)  tmp[0] = tmp2[0];
14179b1997-01-29Per Hedbor  else
0ba0382001-08-28Henrik Grubbström (Grubba)  tmp[0] = "application/octet-stream";
14179b1997-01-29Per Hedbor  }
0ba0382001-08-28Henrik Grubbström (Grubba)  } else if (!(tmp = types_fun("default"))) {
9be5aa1998-07-03Henrik Grubbström (Grubba)  tmp = ({ "application/octet-stream", 0 });
14179b1997-01-29Per Hedbor  }
9be5aa1998-07-03Henrik Grubbström (Grubba)  return to?tmp:tmp[0];
b1fca01996-11-12Per Hedbor }
e351dd1999-11-29Per Hedbor array (RoxenModule) get_providers(string provides)
2f1e892000-08-15Martin Nilsson //! Returns an array with all provider modules that provides "provides".
ae32d01998-03-23David Hedbor {
2f1e892000-08-15Martin Nilsson  // This cache is cleared in the invalidate_cache() call.
ae32d01998-03-23David Hedbor  if(!provider_module_cache[provides])
10c7e11999-12-28Martin Nilsson  {
ae32d01998-03-23David Hedbor  int i; provider_module_cache[provides] = ({ }); for(i = 9; i >= 0; i--) {
10c7e11999-12-28Martin Nilsson  foreach(indices(pri[i]->provider_modules), RoxenModule d) if(pri[i]->provider_modules[ d ][ provides ])
ae32d01998-03-23David Hedbor  provider_module_cache[provides] += ({ d }); } } return provider_module_cache[provides]; }
14179b1997-01-29Per Hedbor 
e351dd1999-11-29Per Hedbor RoxenModule get_provider(string provides)
2f1e892000-08-15Martin Nilsson //! Returns the first provider module that provides "provides".
ae32d01998-03-23David Hedbor {
e351dd1999-11-29Per Hedbor  array (RoxenModule) prov = get_providers(provides);
ae32d01998-03-23David Hedbor  if(sizeof(prov)) return prov[0]; return 0; }
bdb8da1998-09-02Johan Schön array(mixed) map_providers(string provides, string fun, mixed ... args)
2f1e892000-08-15Martin Nilsson //! Maps the function "fun" over all matching provider modules.
ae32d01998-03-23David Hedbor {
e351dd1999-11-29Per Hedbor  array (RoxenModule) prov = get_providers(provides);
0e1f262002-01-29Martin Stjernholm  mixed error;
bdb8da1998-09-02Johan Schön  array a=({ }); mixed m;
10c7e11999-12-28Martin Nilsson  foreach(prov, RoxenModule mod)
9bb8131998-09-12Per Hedbor  {
ae32d01998-03-23David Hedbor  if(!objectp(mod)) continue;
10c7e11999-12-28Martin Nilsson  if(functionp(mod[fun]))
bdb8da1998-09-02Johan Schön  error = catch(m=mod[fun](@args));
0e1f262002-01-29Martin Stjernholm  if(error) { report_debug("Error in map_providers(): " + describe_backtrace(error));
24fbd41999-04-21David Hedbor  }
bdb8da1998-09-02Johan Schön  else
9bb8131998-09-12Per Hedbor  a += ({ m });
18be211998-05-07Henrik Grubbström (Grubba)  error = 0;
ae32d01998-03-23David Hedbor  }
9bb8131998-09-12Per Hedbor  return a;
ae32d01998-03-23David Hedbor } mixed call_provider(string provides, string fun, mixed ... args)
2f1e892000-08-15Martin Nilsson //! Maps the function "fun" over all matching provider modules and //! returns the first positive response.
ae32d01998-03-23David Hedbor {
10c7e11999-12-28Martin Nilsson  foreach(get_providers(provides), RoxenModule mod)
e351dd1999-11-29Per Hedbor  {
d8b7721998-05-28Henrik Grubbström (Grubba)  function f; if(objectp(mod) && functionp(f = mod[fun])) {
a51a902001-11-12Martin Stjernholm  mixed ret; if (ret = f(@args)) { return ret;
d8b7721998-05-28Henrik Grubbström (Grubba)  } }
ae32d01998-03-23David Hedbor  } }
14179b1997-01-29Per Hedbor 
517c7e2000-09-30Per Hedbor array (function) file_extension_modules(string ext)
b1fca01996-11-12Per Hedbor {
0ba0382001-08-28Henrik Grubbström (Grubba)  if(!file_extension_module_cache[ext = lower_case(ext)])
10c7e11999-12-28Martin Nilsson  {
b1fca01996-11-12Per Hedbor  int i; file_extension_module_cache[ext] = ({ }); for(i=9; i>=0; i--) {
e351dd1999-11-29Per Hedbor  array(RoxenModule) d; RoxenModule p;
b1fca01996-11-12Per Hedbor  if(d = pri[i]->file_extension_modules[ext]) foreach(d, p) file_extension_module_cache[ext] += ({ p->handle_file_extension }); } } return file_extension_module_cache[ext]; }
517c7e2000-09-30Per Hedbor array (function) url_modules()
b1fca01996-11-12Per Hedbor { if(!url_module_cache) { int i; url_module_cache=({ }); for(i=9; i>=0; i--) {
e351dd1999-11-29Per Hedbor  array(RoxenModule) d; RoxenModule p;
b1fca01996-11-12Per Hedbor  if(d=pri[i]->url_modules) foreach(d, p) url_module_cache += ({ p->remap_url }); } } return url_module_cache; }
9a8a152000-09-25Per Hedbor static mapping api_module_cache = ([]);
e351dd1999-11-29Per Hedbor mapping api_functions(void|RequestID id)
4f4bc11998-02-04Per Hedbor {
fc9d8e2000-08-28Per Hedbor  return api_module_cache+([]);
4f4bc11998-02-04Per Hedbor }
517c7e2000-09-30Per Hedbor array (function) logger_modules()
b1fca01996-11-12Per Hedbor { if(!logger_module_cache) { int i; logger_module_cache=({ }); for(i=9; i>=0; i--) {
e351dd1999-11-29Per Hedbor  array(RoxenModule) d; RoxenModule p;
b1fca01996-11-12Per Hedbor  if(d=pri[i]->logger_modules) foreach(d, p) if(p->log) logger_module_cache += ({ p->log }); } } return logger_module_cache; }
517c7e2000-09-30Per Hedbor array (function) last_modules()
b1fca01996-11-12Per Hedbor { if(!last_module_cache) { int i; last_module_cache=({ }); for(i=9; i>=0; i--) {
e351dd1999-11-29Per Hedbor  array(RoxenModule) d; RoxenModule p;
b1fca01996-11-12Per Hedbor  if(d=pri[i]->last_modules) foreach(d, p) if(p->last_resort) last_module_cache += ({ p->last_resort }); } } return last_module_cache; }
ca44e51998-07-02Henrik Grubbström (Grubba) #ifdef __NT__
e351dd1999-11-29Per Hedbor static mixed strip_fork_information(RequestID id)
ca44e51998-07-02Henrik Grubbström (Grubba) { array a = id->not_query/"::";
9934d62001-09-05Jonas Wallden  // 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];
ca44e51998-07-02Henrik Grubbström (Grubba)  id->misc->fork_information = a[1..];
c5e0961999-10-04Per Hedbor  return 0;
ca44e51998-07-02Henrik Grubbström (Grubba) } #endif /* __NT__ */
517c7e2000-09-30Per Hedbor array (function) first_modules()
b1fca01996-11-12Per Hedbor { if(!first_module_cache) { int i;
ca44e51998-07-02Henrik Grubbström (Grubba)  first_module_cache=({ #ifdef __NT__ strip_fork_information, // Always first! #endif /* __NT__ */ });
b1fca01996-11-12Per Hedbor  for(i=9; i>=0; i--) {
e351dd1999-11-29Per Hedbor  array(RoxenModule) d; RoxenModule p;
f128901997-08-15Henrik Grubbström (Grubba)  if(d=pri[i]->first_modules) { foreach(d, p) { if(p->first_try) {
b1fca01996-11-12Per Hedbor  first_module_cache += ({ p->first_try });
f128901997-08-15Henrik Grubbström (Grubba)  } } }
b1fca01996-11-12Per Hedbor  } }
f128901997-08-15Henrik Grubbström (Grubba) 
b1fca01996-11-12Per Hedbor  return first_module_cache; }
4d10232001-06-26Per Hedbor void set_userdb_module_cache( array to ) // Used by the config_filesystem.pike module to enforce the usage of // the config userdb module, for now. { userdb_module_cache = to; }
3342dd2001-01-19Per Hedbor array(UserDB) user_databases() { if( userdb_module_cache ) return userdb_module_cache; array tmp = ({}); foreach( values( modules ), mapping m ) foreach( values(m->copies), RoxenModule mo ) if( mo->module_type & MODULE_USERDB ) tmp += ({ ({ mo->query( "_priority" ), mo }) }); sort( tmp );
96d86e2001-01-29Per Hedbor // tmp += ({ ({ 0, roxen->config_userdb_module }) });
3342dd2001-01-19Per Hedbor  return userdb_module_cache = reverse(column(tmp,1)); } array(AuthModule) auth_modules() { if( auth_module_cache ) return auth_module_cache; array tmp = ({}); foreach( values( modules ), mapping m ) foreach( values(m->copies), RoxenModule mo ) if( mo->module_type & MODULE_AUTH ) tmp += ({ ({ mo->query( "_priority" ), mo }) }); sort( tmp ); return auth_module_cache = reverse(column(tmp,1)); }
b1fca01996-11-12Per Hedbor 
517c7e2000-09-30Per Hedbor array location_modules()
3342dd2001-01-19Per Hedbor //! Return an array of all location modules the request should be
cd92872000-08-15Johan Sundström //! mapped through, by order of priority.
b1fca01996-11-12Per Hedbor { if(!location_module_cache) { int i;
8cc31b1997-10-12Henrik Grubbström (Grubba)  array new_location_module_cache=({ });
b1fca01996-11-12Per Hedbor  for(i=9; i>=0; i--) {
10c7e11999-12-28Martin Nilsson  array(RoxenModule) d;
e351dd1999-11-29Per Hedbor  RoxenModule p;
8cc31b1997-10-12Henrik Grubbström (Grubba)  if(d=pri[i]->location_modules) { array level_find_files = ({}); array level_locations = ({}); foreach(d, p) { string location; // FIXME: Should there be a catch() here? if(p->find_file && (location = p->query_location())) { level_find_files += ({ p->find_file }); level_locations += ({ location }); } }
dffddc2000-10-10Johan Sundström  sort(map(level_locations, sizeof), level_locations, level_find_files);
8cc31b1997-10-12Henrik Grubbström (Grubba)  int j; for (j = sizeof(level_locations); j--;) { // Order after longest path first. new_location_module_cache += ({ ({ level_locations[j], level_find_files[j] }) }); } }
b1fca01996-11-12Per Hedbor  }
8cc31b1997-10-12Henrik Grubbström (Grubba)  location_module_cache = new_location_module_cache;
b1fca01996-11-12Per Hedbor  } return location_module_cache; }
517c7e2000-09-30Per Hedbor array(function) filter_modules()
b1fca01996-11-12Per Hedbor { if(!filter_module_cache) { int i; filter_module_cache=({ }); for(i=9; i>=0; i--) {
10c7e11999-12-28Martin Nilsson  array(RoxenModule) d;
e351dd1999-11-29Per Hedbor  RoxenModule p;
b1fca01996-11-12Per Hedbor  if(d=pri[i]->filter_modules) foreach(d, p) if(p->filter) filter_module_cache+=({ p->filter }); } } return filter_module_cache; }
1c78232000-03-13Per Hedbor void init_log_file() { if(log_function) { // Free the old one. destruct(function_object(log_function)); log_function = 0; } // Only try to open the log file if logging is enabled!! if(query("Log")) { string logfile = query("LogFile");
f7d9811997-09-12Per Hedbor  if(strlen(logfile))
f3ca762000-08-19Per Hedbor  log_function = roxen.LogFile( logfile )->write;
1c78232000-03-13Per Hedbor  }
b1fca01996-11-12Per Hedbor }
14179b1997-01-29Per Hedbor // Parse the logging format strings. private inline string fix_logging(string s)
b1fca01996-11-12Per Hedbor {
f3ca762000-08-19Per Hedbor  sscanf(s, "%*[\t ]%s", s);
14179b1997-01-29Per Hedbor  return s;
b1fca01996-11-12Per Hedbor }
14179b1997-01-29Per Hedbor private void parse_log_formats() { string b; array foo=query("LogFormat")/"\n"; foreach(foo, b) if(strlen(b) && b[0] != '#' && sizeof(b/":")>1)
7a243b2000-08-19Per Hedbor  log_format[(int)(b/":")[0]] = fix_logging((b/":")[1..]*":");
14179b1997-01-29Per Hedbor }
b1fca01996-11-12Per Hedbor 
9c19002001-02-27Per Hedbor void log(mapping file, RequestID request_id)
14179b1997-01-29Per Hedbor {
6533f22001-08-23Martin Nilsson  // Call all logging functions foreach(logger_module_cache||logger_modules(), function f)
f3ca762000-08-19Per Hedbor  if( f( request_id, file ) ) return;
14179b1997-01-29Per Hedbor 
7a243b2000-08-19Per Hedbor  if( !log_function )
6533f22001-08-23Martin Nilsson  return; // No file is open for logging.
14179b1997-01-29Per Hedbor 
7a243b2000-08-19Per Hedbor  if(do_not_log_patterns && Roxen._match(request_id->remoteaddr, do_not_log_patterns))
14179b1997-01-29Per Hedbor  return;
10c7e11999-12-28Martin Nilsson 
7a243b2000-08-19Per Hedbor  string form; if(!(form=log_format[file->error])) form = log_format[0];
14179b1997-01-29Per Hedbor  if(!form) return;
7a243b2000-08-19Per Hedbor  roxen.run_log_format( form, log_function, request_id, file );
14179b1997-01-29Per Hedbor }
9c19002001-02-27Per Hedbor array(string) userinfo(string u, RequestID|void id)
6533f22001-08-23Martin Nilsson //! @note //! DEPRECATED COMPATIBILITY FUNCTION
3342dd2001-01-19Per Hedbor //!
cd81922000-09-19Johan Sundström //! Fetches user information from the authentication module by calling //! its userinfo() method. Returns zero if no auth module was present.
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
14179b1997-01-29Per Hedbor {
3342dd2001-01-19Per Hedbor  User uid; foreach( user_databases(), UserDB m ) if( uid = m->find_user( u ) )
ac77452001-06-13Per Hedbor  return uid->compat_userinfo(id);
14179b1997-01-29Per Hedbor }
9c19002001-02-27Per Hedbor array(string) userlist(RequestID|void id)
6533f22001-08-23Martin Nilsson //! @note //! DEPRECATED COMPATIBILITY FUNCTION
3342dd2001-01-19Per Hedbor //!
cd81922000-09-19Johan Sundström //! Fetches the full list of valid usernames from the authentication //! module by calling its userlist() method. Returns zero if no auth //! module was present.
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
14179b1997-01-29Per Hedbor {
3342dd2001-01-19Per Hedbor  array(string) list = ({}); foreach( user_databases(), UserDB m )
ac77452001-06-13Per Hedbor  list |= m->list_users(id);
3342dd2001-01-19Per Hedbor  return list;
14179b1997-01-29Per Hedbor }
9c19002001-02-27Per Hedbor array(string) user_from_uid(int u, RequestID|void id)
6533f22001-08-23Martin Nilsson //! @note //! DEPRECATED COMPATIBILITY FUNCTION
3342dd2001-01-19Per Hedbor //!
cd81922000-09-19Johan Sundström //! Return the user data for id u from the authentication module. The //! id parameter might be left out if FTP. Returns zero if no auth //! module was present.
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
14179b1997-01-29Per Hedbor {
3342dd2001-01-19Per Hedbor  User uid; foreach( user_databases(), UserDB m )
ac77452001-06-13Per Hedbor  if( uid = m->find_user_from_uid( u,id ) )
3342dd2001-01-19Per Hedbor  return uid->compat_userinfo();
14179b1997-01-29Per Hedbor }
e3f4662001-01-19Per Hedbor UserDB find_user_database( string name )
96d86e2001-01-29Per Hedbor //! Given a user database name, returns it if it exists in this //! configuration, otherwise returns 0.
e3f4662001-01-19Per Hedbor { foreach( user_databases(), UserDB m ) if( m->name == name ) return m; } AuthModule find_auth_module( string name )
96d86e2001-01-29Per Hedbor //! Given a authentication method name, returns it if it exists in //! this configuration, otherwise returns 0.
e3f4662001-01-19Per Hedbor { foreach( auth_modules(), AuthModule m ) if( m->name == name ) return m; }
3342dd2001-01-19Per Hedbor 
96d86e2001-01-29Per Hedbor User authenticate( RequestID id, UserDB|void database)
3342dd2001-01-19Per Hedbor //! Try to authenticate the request with users from the specified user //! database. If no @[database] is specified, all datbases in the
96d86e2001-01-29Per Hedbor //! current configuration are searched in priority order.
3342dd2001-01-19Per Hedbor //! //! The return value is the autenticated user.
0cde962001-01-21Per Hedbor //! id->misc->authenticated_user is always set to the return value.
3342dd2001-01-19Per Hedbor { User u;
61636c2004-04-29Martin Stjernholm  if (!zero_type (u = id->misc->authenticated_user)) return u;
9a4c052001-01-28Per Hedbor  foreach( auth_modules(), AuthModule method ) if( u = method->authenticate( id, database ) ) return id->misc->authenticated_user = u;
3342dd2001-01-19Per Hedbor }
96d86e2001-01-29Per Hedbor mapping authenticate_throw( RequestID id, string realm, UserDB|void database)
3342dd2001-01-19Per Hedbor //! Returns a reply mapping, similar to @[Roxen.http_rxml_reply] with //! friends. If no @[database] is specified, all datbases in the
96d86e2001-01-29Per Hedbor //! current configuration are searched in priority order.
3342dd2001-01-19Per Hedbor { mapping m;
9a4c052001-01-28Per Hedbor  foreach( auth_modules(), AuthModule method ) if( m = method->authenticate_throw( id, realm, database ) ) return m;
96d86e2001-01-29Per Hedbor } User find_user( string user, RequestID|void id ) //! Tries to find the specified user in the currently available user //! databases. If id is specified, this function defaults to the //! database that the currently authenticated user came from, if any. //! //! The other user databases are processed in priority order
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
96d86e2001-01-29Per Hedbor { User uid;
d2fcaf2001-01-30Per Hedbor  if( id && id->misc->authenticated_user
ac77452001-06-13Per Hedbor  && ( uid = id->misc->authenticated_user->database->find_user(user,id)))
96d86e2001-01-29Per Hedbor  return uid; foreach( user_databases(), UserDB m )
ac77452001-06-13Per Hedbor  if( uid = m->find_user( user,id ) )
96d86e2001-01-29Per Hedbor  return uid; }
ac77452001-06-13Per Hedbor array(string) list_users(RequestID|void id)
d2fcaf2001-01-30Per Hedbor //! Fetches the full list of valid usernames from the authentication //! modules by calling the list-users() methods.
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
d2fcaf2001-01-30Per Hedbor { array(string) list = ({}); foreach( user_databases(), UserDB m )
ac77452001-06-13Per Hedbor  list |= m->list_users(id);
d2fcaf2001-01-30Per Hedbor  return list; }
ac77452001-06-13Per Hedbor array(string) list_groups(RequestID|void id)
d2fcaf2001-01-30Per Hedbor //! Fetches the full list of valid groupnames from the authentication //! modules by calling the list-users() methods.
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
d2fcaf2001-01-30Per Hedbor { array(string) list = ({}); foreach( user_databases(), UserDB m )
ac77452001-06-13Per Hedbor  list |= m->list_groups(id);
d2fcaf2001-01-30Per Hedbor  return list; }
96d86e2001-01-29Per Hedbor Group find_group( string group, RequestID|void id ) //! Tries to find the specified group in the currently available user //! databases. If id is specified, this function defaults to the //! database that the currently authenticated user came from, if any. //! //! The other user databases are processed in priority order
ac77452001-06-13Per Hedbor //! //! Note that you should always supply id if it's possible, some user //! databases require it (such as the htaccess database)
96d86e2001-01-29Per Hedbor { Group uid;
d2fcaf2001-01-30Per Hedbor  if( id && id->misc->authenticated_user
96d86e2001-01-29Per Hedbor  && ( uid = id->misc->authenticated_user->database->find_group( group ) )) return uid; foreach( user_databases(), UserDB m )
ac77452001-06-13Per Hedbor  if( uid = m->find_group( group,id ) )
96d86e2001-01-29Per Hedbor  return uid;
3342dd2001-01-19Per Hedbor }
9c19002001-02-27Per Hedbor string last_modified_by(Stdio.File file, RequestID id)
6103bc1999-10-09Henrik Grubbström (Grubba) {
1f4a6c2000-08-28Per Hedbor  Stat s;
6103bc1999-10-09Henrik Grubbström (Grubba)  int uid;
9f9fc32000-02-17Per Hedbor  array u;
10c7e11999-12-28Martin Nilsson 
6103bc1999-10-09Henrik Grubbström (Grubba)  if(objectp(file)) s=file->stat(); if(!s || sizeof(s)<5) return "A. Nonymous"; uid=s[5]; u=user_from_uid(uid, id); if(u) return u[0]; return "A. Nonymous"; }
14179b1997-01-29Per Hedbor  // Some clients does _not_ handle the magic 'internal-gopher-...'. // So, lets do it here instead. private mapping internal_gopher_image(string from) { sscanf(from, "%s.gif", from); sscanf(from, "%s.jpg", from); from -= "."; // Disallow "internal-gopher-..", it won't really do much harm, but a list of // all files in '..' might be retrieved (that is, the actual directory // file was sent to the browser)
1c78232000-03-13Per Hedbor  Stdio.File f = lopen("roxen-images/dir/"+from+".gif","r"); if (f)
5848842000-08-28Per Hedbor  return (["file":f, "type":"image/gif", "stat":f->stat(),]); else
06026c1999-10-19Henrik Grubbström (Grubba)  return 0;
5848842000-08-28Per Hedbor  // File not found.
14179b1997-01-29Per Hedbor } #ifdef MODULE_LEVEL_SECURITY
5910aa2004-02-17Martin Stjernholm private mapping(RoxenModule:array) security_level_cache = set_weak_flag (([]), 1);
14179b1997-01-29Per Hedbor 
3e3bab2001-01-19Per Hedbor int|mapping check_security(function|RoxenModule a, RequestID id, void|int slevel)
14179b1997-01-29Per Hedbor { array seclevels;
12a9c51997-08-11Henrik Grubbström (Grubba)  // NOTE: // ip_ok and auth_ok are three-state variables. // Valid contents for them are: // 0 Unknown state -- No such restriction encountered yet. // 1 May be bad -- Restriction encountered, and test failed. // ~0 OK -- Test passed.
1935351997-04-28Henrik Grubbström (Grubba) 
5910aa2004-02-17Martin Stjernholm  if (RoxenModule mod = Roxen.get_owning_module (a)) { // Only store the module objects in the cache and not `a' directly // since it can be (in) an object that is very short lived. if (!(seclevels = security_level_cache[mod])) { if(mod->query_seclevels) seclevels = ({ mod->query_seclevels(), mod->query("_seclvl"), }); else seclevels = ({0,0}); security_level_cache[mod] = seclevels; }
2b86422000-06-29Martin Stjernholm  }
5910aa2004-02-17Martin Stjernholm  else seclevels = ({0,0});
14179b1997-01-29Per Hedbor 
bc0fa02001-03-08Per Hedbor  if(slevel && (seclevels[1] > slevel)) // "Trustlevel" to low.
5a42932001-08-30Per Hedbor  // Regarding memory cache: This won't have any impact, since it's // always the same, regardless of the client requesting the file.
14179b1997-01-29Per Hedbor  return 1;
10c7e11999-12-28Martin Nilsson 
18be211998-05-07Henrik Grubbström (Grubba)  mixed err;
bc0fa02001-03-08Per Hedbor  if( function(RequestID:int|mapping) f = seclevels[0] )
5a42932001-08-30Per Hedbor  // And here we don't have to take notice of the RAM-cache either, // since the security patterns themselves does that. // // All patterns that varies depending on the client must use // NOCACHE(), to force the request to be uncached. //
bc0fa02001-03-08Per Hedbor  err=catch { return f( id ); }; else return 0; // Ok if there are no patterns.
18be211998-05-07Henrik Grubbström (Grubba) 
bc0fa02001-03-08Per Hedbor  report_error("check_security(): %s:\n%s\n", LOC_M(39, "Error during module security check"), describe_backtrace(err));
18be211998-05-07Henrik Grubbström (Grubba) 
bc0fa02001-03-08Per Hedbor  return 1;
14179b1997-01-29Per Hedbor } #endif // Empty all the caches above.
8cc31b1997-10-12Henrik Grubbström (Grubba) void invalidate_cache()
14179b1997-01-29Per Hedbor { last_module_cache = 0; filter_module_cache = 0;
3342dd2001-01-19Per Hedbor  userdb_module_cache = 0; auth_module_cache = 0;
14179b1997-01-29Per Hedbor  first_module_cache = 0; url_module_cache = 0; location_module_cache = 0; logger_module_cache = 0; file_extension_module_cache = ([]);
ae32d01998-03-23David Hedbor  provider_module_cache = ([]);
14179b1997-01-29Per Hedbor #ifdef MODULE_LEVEL_SECURITY
5910aa2004-02-17Martin Stjernholm  security_level_cache = set_weak_flag (([ ]), 1);
14179b1997-01-29Per Hedbor #endif }
ec058c1998-07-04Henrik Grubbström (Grubba) // Empty all the caches above AND the ones in the loaded modules. void clear_memory_caches() { invalidate_cache();
10c7e11999-12-28Martin Nilsson  foreach(indices(otomod), RoxenModule m) if (m && m->clear_memory_caches) if (mixed err = catch( m->clear_memory_caches() ))
434bac2000-07-14Andreas Lange  report_error("clear_memory_caches() "+
49cd282000-08-11Andreas Lange  LOC_M(40, "failed for module %O:\n%s\n"),
67f60e2000-07-09Martin Nilsson  otomod[m], describe_backtrace(err));
ec058c1998-07-04Henrik Grubbström (Grubba) }
7de44b2000-09-13Jonas Wallden // Returns tuple < image, mime-type >
1b664a2004-03-08Jonas Wallden static array(string) draw_saturation_bar(int hue,int brightness, int where, int small_version)
fc94331997-10-25Per Hedbor {
1b664a2004-03-08Jonas Wallden  Image.Image bar = small_version ? Image.Image(16, 128) : Image.Image(30, 256);
fc94331997-10-25Per Hedbor  for(int i=0;i<128;i++) {
4205aa2004-03-06Jonas Wallden  int j = i * 2; array color = hsv_to_rgb(hue, 255 - j, brightness);
1b664a2004-03-08Jonas Wallden  if (small_version) { bar->line(0, i, 15, i, @color); } else { bar->line(0, j, 29, j, @color); bar->line(0, j + 1,29, j + 1, @color); }
fc94331997-10-25Per Hedbor  }
e2d5772004-03-13Jonas Wallden  if (where >= 0 && where <= 255) { where = 255 - where; int hilite = (brightness > 128) ? 0 : 255; if (small_version) bar->line(0, where / 2, 15, where / 2, hilite, hilite, hilite); else bar->line(0, where, 29, where, hilite, hilite, hilite); }
1b664a2004-03-08Jonas Wallden 
2a346d2000-09-19Per Hedbor #if constant(Image.JPEG) && constant(Image.JPEG.encode)
7de44b2000-09-13Jonas Wallden  return ({ Image.JPEG.encode(bar), "image/jpeg" });
2a346d2000-09-19Per Hedbor #else return ({ Image.PNG.encode(bar), "image/png" });
7de44b2000-09-13Jonas Wallden #endif
fc94331997-10-25Per Hedbor }
14179b1997-01-29Per Hedbor // Inspired by the internal-gopher-... thingie, this is the images
a6ef1f2000-03-28Johan Sundström // from the administration interface. :-)
2a346d2000-09-19Per Hedbor private mapping internal_roxen_image( string from, RequestID id )
14179b1997-01-29Per Hedbor { sscanf(from, "%s.gif", from); sscanf(from, "%s.jpg", from);
2b658c2000-02-07Per Hedbor  sscanf(from, "%s.xcf", from); sscanf(from, "%s.png", from);
fc94331997-10-25Per Hedbor 
1c78232000-03-13Per Hedbor  // Automatically generated colorbar. Used by wizard code...
fc94331997-10-25Per Hedbor  int hue,bright,w;
1b664a2004-03-08Jonas Wallden  string colorbar; if(sscanf(from, "%s:%d,%d,%d", colorbar, hue, bright,w)==4) { array bar = draw_saturation_bar(hue, bright, w, colorbar == "colorbar-small");
7de44b2000-09-13Jonas Wallden  return Roxen.http_string_answer(bar[0], bar[1]); }
fc94331997-10-25Per Hedbor 
2b658c2000-02-07Per Hedbor  Stdio.File f;
7310762000-09-19Per Hedbor  if( !id->misc->internal_get ) if(f = lopen("roxen-images/"+from+".gif", "r")) return (["file":f, "type":"image/gif", "stat":f->stat()]);
1c78232000-03-13Per Hedbor  if(f = lopen("roxen-images/"+from+".png", "r"))
5848842000-08-28Per Hedbor  return (["file":f, "type":"image/png", "stat":f->stat()]);
7310762000-09-19Per Hedbor  if(f = lopen("roxen-images/"+from+".jpg", "r")) return (["file":f, "type":"image/jpeg", "stat":f->stat()]);
1c78232000-03-13Per Hedbor  if(f = lopen("roxen-images/"+from+".xcf", "r"))
5848842000-08-28Per Hedbor  return (["file":f, "type":"image/x-gimp-image", "stat":f->stat()]);
7310762000-09-19Per Hedbor  if(f = lopen("roxen-images/"+from+".gif", "r")) return (["file":f, "type":"image/gif", "stat":f->stat()]);
2b658c2000-02-07Per Hedbor  // File not found. return 0;
14179b1997-01-29Per Hedbor } mapping (mixed:function|int) locks = ([]); #ifdef THREADS
e5bad21998-02-10Per Hedbor // import Thread;
e6aff01997-05-25Henrik Grubbström (Grubba) 
55a89e1997-09-14Per Hedbor mapping locked = ([]), thread_safe = ([]);
e351dd1999-11-29Per Hedbor mixed _lock(object|function f)
14179b1997-01-29Per Hedbor {
3e3bab2001-01-19Per Hedbor  Thread.MutexKey key;
1fab6f1997-09-03Henrik Grubbström (Grubba)  function|int l;
9c19002001-02-27Per Hedbor  TIMER_START(module_lock);
1fab6f1997-09-03Henrik Grubbström (Grubba)  if (functionp(f)) { f = function_object(f); }
55a89e1997-09-14Per Hedbor  if (l = locks[f]) { if (l != -1) {
1fab6f1997-09-03Henrik Grubbström (Grubba)  // Allow recursive locks.
beb1f21998-05-23Mattias Wingstedt  catch{
91d3c32001-03-12Martin Nilsson  // report_debug("lock %O\n", f);
55a89e1997-09-14Per Hedbor  locked[f]++;
1fab6f1997-09-03Henrik Grubbström (Grubba)  key = l();
beb1f21998-05-23Mattias Wingstedt  };
55a89e1997-09-14Per Hedbor  } else thread_safe[f]++;
1fab6f1997-09-03Henrik Grubbström (Grubba)  } else if (f->thread_safe) { locks[f]=-1;
55a89e1997-09-14Per Hedbor  thread_safe[f]++;
14179b1997-01-29Per Hedbor  } else {
55a89e1997-09-14Per Hedbor  if (!locks[f]) {
1fab6f1997-09-03Henrik Grubbström (Grubba)  // Needed to avoid race-condition.
e5bad21998-02-10Per Hedbor  l = Thread.Mutex()->lock;
1fab6f1997-09-03Henrik Grubbström (Grubba)  if (!locks[f]) { locks[f]=l; }
14179b1997-01-29Per Hedbor  }
91d3c32001-03-12Martin Nilsson  // report_debug("lock %O\n", f);
55a89e1997-09-14Per Hedbor  locked[f]++;
1fab6f1997-09-03Henrik Grubbström (Grubba)  key = l();
b1fca01996-11-12Per Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(module_lock);
14179b1997-01-29Per Hedbor  return key;
b1fca01996-11-12Per Hedbor }
14179b1997-01-29Per Hedbor #define LOCK(X) key=_lock(X)
d7b0871997-08-31Per Hedbor #define UNLOCK() do{key=0;}while(0)
14179b1997-01-29Per Hedbor #else #define LOCK(X)
c95bd51998-01-30Henrik Grubbström (Grubba) #define UNLOCK()
14179b1997-01-29Per Hedbor #endif
a1334f1998-02-20Mirar (Pontus Hagland) string examine_return_mapping(mapping m) { string res; if (m->extra_heads) m->extra_heads=mkmapping(Array.map(indices(m->extra_heads), lower_case), values(m->extra_heads)); else m->extra_heads=([]); switch (m->error||200) { case 302: // redirect
10c7e11999-12-28Martin Nilsson  if (m->extra_heads &&
a1334f1998-02-20Mirar (Pontus Hagland)  (m->extra_heads->location))
dff8322003-10-20Martin Stjernholm  res = sprintf("Returned redirect to %O ", m->extra_heads->location);
a1334f1998-02-20Mirar (Pontus Hagland)  else
1a89f42000-08-14Martin Stjernholm  res = "Returned redirect, but no location header. ";
a1334f1998-02-20Mirar (Pontus Hagland)  break; case 401: if (m->extra_heads["www-authenticate"])
dff8322003-10-20Martin Stjernholm  res = sprintf("Returned authentication failed: %O ",
67f60e2000-07-09Martin Nilsson  m->extra_heads["www-authenticate"]);
a1334f1998-02-20Mirar (Pontus Hagland)  else
1a89f42000-08-14Martin Stjernholm  res = "Returned authentication failed. ";
a1334f1998-02-20Mirar (Pontus Hagland)  break; case 200:
1a89f42000-08-14Martin Stjernholm  res = "Returned ok. ";
a1334f1998-02-20Mirar (Pontus Hagland)  break;
a8f1b32000-01-31Per Hedbor 
a1334f1998-02-20Mirar (Pontus Hagland)  default:
dff8322003-10-20Martin Stjernholm  res = sprintf("Returned %O. ", m->error);
a1334f1998-02-20Mirar (Pontus Hagland)  } if (!zero_type(m->len)) if (m->len<0)
434bac2000-07-14Andreas Lange  res += "No data ";
a1334f1998-02-20Mirar (Pontus Hagland)  else
dff8322003-10-20Martin Stjernholm  res += sprintf("%O bytes ", m->len);
a1334f1998-02-20Mirar (Pontus Hagland)  else if (stringp(m->data))
434bac2000-07-14Andreas Lange  res += sprintf("%d bytes ", strlen(m->data));
a1334f1998-02-20Mirar (Pontus Hagland)  else if (objectp(m->file)) if (catch {
1f4a6c2000-08-28Per Hedbor  Stat a=m->file->stat();
dff8322003-10-20Martin Stjernholm  res += sprintf("%O bytes ", a[1]-m->file->tell());
b461641998-10-11Henrik Grubbström (Grubba)  })
1a89f42000-08-14Martin Stjernholm  res += "? bytes ";
a1334f1998-02-20Mirar (Pontus Hagland) 
1a89f42000-08-14Martin Stjernholm  if (m->data) res += "(static)";
434bac2000-07-14Andreas Lange  else if (m->file) res += "(open file)";
a1334f1998-02-20Mirar (Pontus Hagland) 
dffa222000-12-10Per Hedbor  if (stringp(m->extra_heads["content-type"]) ||
b461641998-10-11Henrik Grubbström (Grubba)  stringp(m->type)) {
dff8322003-10-20Martin Stjernholm  res += sprintf(" of %O", m->type||m->extra_heads["content-type"]);
b461641998-10-11Henrik Grubbström (Grubba)  }
a1334f1998-02-20Mirar (Pontus Hagland) 
67f60e2000-07-09Martin Nilsson  res+="<br />";
a1334f1998-02-20Mirar (Pontus Hagland)  return res; }
c5e0961999-10-04Per Hedbor 
3e09172004-05-03Henrik Grubbström (Grubba) //! Find all applicable locks for this user on @[path]. multiset(DAVLock) find_locks(string path, int(0..1) recursive, int(0..1) exclude_shared, RequestID id) {
3681412004-05-07Henrik Grubbström (Grubba)  SIMPLE_TRACE_ENTER(0, "find_locks(%O, %O, %O, X)", path, recursive, exclude_shared);
3e09172004-05-03Henrik Grubbström (Grubba)  multiset(DAVLock) locks = (<>); foreach(location_module_cache||location_modules(), [string loc, function func]) {
3681412004-05-07Henrik Grubbström (Grubba)  SIMPLE_TRACE_ENTER(function_object(func), "Finding locks in %O.", loc);
3e09172004-05-03Henrik Grubbström (Grubba)  string subpath; if (has_prefix(path, loc)) { // path == loc + subpath. subpath = path[sizeof(loc)..]; } else if (recursive && has_prefix(loc, path)) { // loc == path + ignored. subpath = "/"; } else { // Does not apply to this location module.
e4acd92004-05-06Henrik Grubbström (Grubba)  TRACE_LEAVE("Skip this module.");
3e09172004-05-03Henrik Grubbström (Grubba)  continue; }
e4acd92004-05-06Henrik Grubbström (Grubba)  TRACE_ENTER(sprintf("subpath: %O", subpath), function_object(func)->find_locks);
3e09172004-05-03Henrik Grubbström (Grubba)  multiset(DAVLock) sub_locks = function_object(func)->find_locks(subpath, recursive, exclude_shared, id);
e4acd92004-05-06Henrik Grubbström (Grubba)  TRACE_LEAVE(""); if (sub_locks) {
3681412004-05-07Henrik Grubbström (Grubba)  SIMPLE_TRACE_LEAVE("Got some locks: %O", sub_locks);
e4acd92004-05-06Henrik Grubbström (Grubba)  locks |= sub_locks; } else { TRACE_LEAVE("Got no locks."); }
3e09172004-05-03Henrik Grubbström (Grubba)  }
3681412004-05-07Henrik Grubbström (Grubba)  SIMPLE_TRACE_LEAVE("Returning %O", locks);
3e09172004-05-03Henrik Grubbström (Grubba)  return locks; }
38c76b2004-04-30Henrik Grubbström (Grubba) //! Check if there are any applicable locks for this user on @[path].
c85afa2004-05-07Martin Stjernholm DAVLock|LockFlag check_locks(string path, int(0..1) recursive, RequestID id)
38c76b2004-04-30Henrik Grubbström (Grubba) {
c85afa2004-05-07Martin Stjernholm  LockFlag state = 0;
38c76b2004-04-30Henrik Grubbström (Grubba)  foreach(location_module_cache||location_modules(), [string loc, function func]) { string subpath;
c85afa2004-05-07Martin Stjernholm  int check_above;
38c76b2004-04-30Henrik Grubbström (Grubba)  if (has_prefix(path, loc)) { // path == loc + subpath. subpath = path[sizeof(loc)..]; } else if (recursive && has_prefix(loc, path)) { // loc == path + ignored.
c85afa2004-05-07Martin Stjernholm  subpath = ""; check_above = 1;
38c76b2004-04-30Henrik Grubbström (Grubba)  } else { // Does not apply to this location module. continue; }
c85afa2004-05-07Martin Stjernholm  int/*LockFlag*/|DAVLock lock_info =
38c76b2004-04-30Henrik Grubbström (Grubba)  function_object(func)->check_locks(subpath, recursive, id);
9f8a912004-05-04Henrik Grubbström (Grubba)  if (objectp(lock_info)) {
c85afa2004-05-07Martin Stjernholm  if (!check_above) {
9f8a912004-05-04Henrik Grubbström (Grubba)  return lock_info; } else {
c85afa2004-05-07Martin Stjernholm  lock_info = LOCK_OWN_BELOW; // We have a lock on some subpath.
9f8a912004-05-04Henrik Grubbström (Grubba)  } }
c85afa2004-05-07Martin Stjernholm  else if (check_above && (lock_info & 1)) // Convert LOCK_*_AT to LOCK_*_BELOW. lock_info &= ~1;
9f8a912004-05-04Henrik Grubbström (Grubba)  if (lock_info > state) state = lock_info;
c85afa2004-05-07Martin Stjernholm  if (state == LOCK_EXCL_AT) return LOCK_EXCL_AT; // Doesn't get any worse.
38c76b2004-04-30Henrik Grubbström (Grubba)  }
9f8a912004-05-04Henrik Grubbström (Grubba)  return state;
38c76b2004-04-30Henrik Grubbström (Grubba) }
4dfab22004-05-14Henrik Grubbström (Grubba) static multiset(DAVLock) active_locks = (<>);
9874072004-05-04Henrik Grubbström (Grubba) //! Unlock the lock represented by @[lock] on @[path].
38c76b2004-04-30Henrik Grubbström (Grubba) //! //! @returns //! Returns a result-mapping on error, and @expr{0@} (zero) on success.
9874072004-05-04Henrik Grubbström (Grubba) mapping(string:mixed) unlock_file(string path, DAVLock lock, RequestID id)
38c76b2004-04-30Henrik Grubbström (Grubba) { // Canonicalize path. if (!has_suffix(path, "/")) path+="/"; foreach(location_module_cache||location_modules(), [string loc, function func]) { if (has_prefix(path, loc)) { // path == loc + subpath. mapping(string:mixed) ret =
9874072004-05-04Henrik Grubbström (Grubba)  function_object(func)->unlock_file(path[sizeof(loc)..], lock, id); // FIXME: Semantics for partial unlocking? if (ret) return ret; } else if (lock->recursive && has_prefix(loc, path)) { // loc == path + ignored. mapping(string:mixed) ret = function_object(func)->unlock_file("/", lock, id);
38c76b2004-04-30Henrik Grubbström (Grubba)  // FIXME: Semantics for partial unlocking? if (ret) return ret; } }
4dfab22004-05-14Henrik Grubbström (Grubba)  active_locks[lock] = 0;
9874072004-05-04Henrik Grubbström (Grubba)  // destruct(lock);
38c76b2004-04-30Henrik Grubbström (Grubba)  return 0; }
4dfab22004-05-14Henrik Grubbström (Grubba) //! Force expiration of any locks that have timed out. int expire_locks(RequestID id) { int t = time(1); int min_time = 0x7fffffff; foreach(active_locks; DAVLock lock;) { if (lock->expiry_time) { if (lock->expiry_time < t) { unlock_file(lock->path, lock, id); } else if (lock->expiry_time < min_time) { min_time = lock->expiry_time; } } } return min_time - t; } static void expire_lock_loop() { int t = expire_locks(0); // NOTE: Called with RequestID 0! if (sizeof(active_locks)) { // Expire locks at least once every hour. if (t < 3600) { roxen.background_run(t, expire_lock_loop); } else { roxen.background_run(3600, expire_lock_loop); } } } //! Refresh a lock. //! //! Update the expiry time for the lock. void refresh_lock(DAVLock lock) { if (lock->expiry_delta) { lock->expiry_time = lock->expiry_delta + time(1); } }
29f2292004-04-28Henrik Grubbström (Grubba) //! Attempt to lock @[path]. //! //! @param path //! Path to lock. //! //! @param locktype //! Type of lock (currently only @expr{"DAV:write"@} is defined). //! //! @param lockscope //! Scope of lock either @expr{"DAV:exclusive"@} or //! @expr{"DAV:shared"@}. //!
d1728c2004-05-14Henrik Grubbström (Grubba) //! @param expiry_delta //! Idle time in seconds before the lock expires. @expr{0@} (zero) //! means no expiry. //!
29f2292004-04-28Henrik Grubbström (Grubba) //! @returns //! Returns a result mapping on failure,
38c76b2004-04-30Henrik Grubbström (Grubba) //! and the resulting @[DAVLock] on success. mapping(string:mixed)|DAVLock lock_file(string path, int(0..1) recursive, string lockscope, string locktype,
fefe702004-05-14Henrik Grubbström (Grubba)  int(0..) expiry_delta,
73f9322004-05-06Martin Stjernholm  array(Parser.XML.Tree.Node) owner,
38c76b2004-04-30Henrik Grubbström (Grubba)  RequestID id)
29f2292004-04-28Henrik Grubbström (Grubba) { // Canonicalize path. if (!has_suffix(path, "/")) path+="/"; // First check if there's already some lock on path that prevents // us from locking it.
c85afa2004-05-07Martin Stjernholm  int/*LockFlag*/|DAVLock lock_info = check_locks(path, recursive, id);
38c76b2004-04-30Henrik Grubbström (Grubba)  if (!intp(lock_info)) { // We already hold a lock that prevents us.
476e9c2004-05-10Henrik Grubbström (Grubba)  if (id->request_headers->if) { return Roxen.http_status(412, "Precondition Failed"); } else { return Roxen.http_status(423, "Locked"); }
c85afa2004-05-07Martin Stjernholm  } else if (lockscope == "DAV:exclusive" ? lock_info >= LOCK_SHARED_BELOW : lock_info >= LOCK_OWN_BELOW) {
38c76b2004-04-30Henrik Grubbström (Grubba)  // Some other lock prevents us. return Roxen.http_status(423, "Locked");
29f2292004-04-28Henrik Grubbström (Grubba)  }
38c76b2004-04-30Henrik Grubbström (Grubba)  // Create the new lock.
29f2292004-04-28Henrik Grubbström (Grubba) 
803cdc2004-05-03Henrik Grubbström (Grubba)  string locktoken = "opaquelocktoken:" + roxen->new_uuid_string();
38c76b2004-04-30Henrik Grubbström (Grubba)  DAVLock lock = DAVLock(locktoken, path, recursive, lockscope, locktype,
fefe702004-05-14Henrik Grubbström (Grubba)  expiry_delta, owner);
29f2292004-04-28Henrik Grubbström (Grubba)  foreach(location_module_cache||location_modules(), [string loc, function func]) { string subpath; if (has_prefix(path, loc)) { // path == loc + subpath. subpath = path[sizeof(loc)..]; } else if (recursive && has_prefix(loc, path)) { // loc == path + ignored. subpath = "/"; } else { // Does not apply to this location module. continue; }
4dfab22004-05-14Henrik Grubbström (Grubba)  mapping(string:mixed) lock_error =
38c76b2004-04-30Henrik Grubbström (Grubba)  function_object(func)->lock_file(subpath, lock, id);
4dfab22004-05-14Henrik Grubbström (Grubba)  if (lock_error) {
9874072004-05-04Henrik Grubbström (Grubba)  // Failure. Unlock the new lock. foreach(location_module_cache||location_modules(), [string loc2, function func2]) { if (has_prefix(path, loc2)) { // path == loc2 + subpath. mapping(string:mixed) ret = function_object(func2)->unlock_file(path[sizeof(loc2)..], lock, id); } else if (recursive && has_prefix(loc2, path)) { // loc2 == path + ignored. mapping(string:mixed) ret = function_object(func2)->unlock_file("/", lock, id); } if (func == func2) break;
29f2292004-04-28Henrik Grubbström (Grubba)  }
9874072004-05-04Henrik Grubbström (Grubba)  // destruct(lock);
4dfab22004-05-14Henrik Grubbström (Grubba)  return lock_error;
29f2292004-04-28Henrik Grubbström (Grubba)  } }
4dfab22004-05-14Henrik Grubbström (Grubba)  if (expiry_delta) { // Lock with timeout. // FIXME: Race-conditions. if (!sizeof(active_locks)) { // Start the lock expiration loop. active_locks[lock] = 1; expire_lock_loop(); } else { active_locks[lock] = 1; } }
29f2292004-04-28Henrik Grubbström (Grubba)  // Success.
38c76b2004-04-30Henrik Grubbström (Grubba)  return lock;
29f2292004-04-28Henrik Grubbström (Grubba) }
cd92872000-08-15Johan Sundström mapping|int(-1..0) low_get_file(RequestID id, int|void no_magic) //! The function that actually tries to find the data requested. All //! modules except last and filter type modules are mapped, in order, //! and the first one that returns a suitable response is used. If //! `no_magic' is set to one, the internal magic roxen images and the
8062042004-04-20Henrik Grubbström (Grubba) //! @[find_internal()] callbacks will be ignored.
cd92872000-08-15Johan Sundström //! //! The return values 0 (no such file) and -1 (the data is a //! directory) are only returned when `no_magic' was set to 1; //! otherwise a result mapping is always generated.
14179b1997-01-29Per Hedbor { #ifdef MODULE_LEVEL_SECURITY int slevel; #endif #ifdef THREADS
3e3bab2001-01-19Per Hedbor  Thread.MutexKey key;
14179b1997-01-29Per Hedbor #endif
db5f6b2001-07-31Per Hedbor  id->not_query = VFS.normalize_path( id->not_query );
5655dc2001-06-06Per Hedbor 
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Request for %s", id->not_query), 0);
14179b1997-01-29Per Hedbor  string file=id->not_query; string loc; function funp; mixed tmp, tmp2;
cd92872000-08-15Johan Sundström  mapping|object(Stdio.File)|int fid;
14179b1997-01-29Per Hedbor  if(!no_magic) {
9c19002001-02-27Per Hedbor  TIMER_START(internal_magic);
41b77c1999-07-15David Hedbor #ifndef NO_INTERNAL_HACK
fd93022000-05-05Martin Nilsson  // Find internal-foo-bar images
41b77c1999-07-15David Hedbor  // min length == 17 (/internal-roxen-?..) // This will save some time indeed.
fd93022000-05-05Martin Nilsson  string type;
67f60e2000-07-09Martin Nilsson  if(sizeof(file) > 17 &&
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 2.1
67f60e2000-07-09Martin Nilsson  (file[0] == '/') &&
cd92872000-08-15Johan Sundström  sscanf(file, "%*s/internal-%s-%[^/]", type, loc) == 3
67f60e2000-07-09Martin Nilsson #else
cd92872000-08-15Johan Sundström  sscanf(file, "/internal-%s-%[^/]", type, loc) == 2
67f60e2000-07-09Martin Nilsson #endif
cd92872000-08-15Johan Sundström  ) {
41b77c1999-07-15David Hedbor  switch(type) {
fd93022000-05-05Martin Nilsson  case "roxen":
d738ba2002-04-10Jonas Wallden  // Mark all /internal-roxen-* as cacheable even though the user might be // authenticated (which normally disables protocol-level caching).
f910602004-05-20Jonas Wallden  RAISE_CACHE(60 * 60 * 24 * 365); // 1 year
beddd12003-11-25Anders Johansson  PROTO_CACHE();
d738ba2002-04-10Jonas Wallden 
a7d0342000-11-13Martin Nilsson  TRACE_LEAVE("Magic internal roxen image");
5eb2832001-01-03Martin Nilsson  if(loc=="unit" || loc=="pixel-of-destiny")
9c19002001-02-27Per Hedbor  { TIMER_END(internal_magic); return (["data":"GIF89a\1\0\1\0\200ÿ\0ÀÀÀ\0\0\0!ù\4\1\0\0\0\0," "\0\0\0\0\1\0\1\0\0\1\1""2\0;",
2f51ba2002-03-22Martin Stjernholm  "type":"image/gif", "stat": ({0, 0, 0, 900000000, 0, 0, 0})]);
9c19002001-02-27Per Hedbor  }
5eb2832001-01-03Martin Nilsson  if(has_prefix(loc, "pixel-"))
9c19002001-02-27Per Hedbor  { TIMER_END(internal_magic); return (["data":sprintf("GIF89a\1\0\1\0\200\0\0\0\0\0%c%c%c,\0\0\0" "\0\1\0\1\0\0\2\2L\1\0;",
5eb2832001-01-03Martin Nilsson  @parse_color(loc[6..])),
2f51ba2002-03-22Martin Stjernholm  "type":"image/gif", "stat": ({0, 0, 0, 900000000, 0, 0, 0})]);
9c19002001-02-27Per Hedbor  } TIMER_END(internal_magic);
2a346d2000-09-19Per Hedbor  return internal_roxen_image(loc, id);
fd93022000-05-05Martin Nilsson 
41b77c1999-07-15David Hedbor  case "gopher":
a7d0342000-11-13Martin Nilsson  TRACE_LEAVE("Magic internal gopher image");
9c19002001-02-27Per Hedbor  TIMER_END(internal_magic);
14179b1997-01-29Per Hedbor  return internal_gopher_image(loc);
41d0f91998-02-20Per Hedbor  }
14179b1997-01-29Per Hedbor  } #endif
10c7e11999-12-28Martin Nilsson 
fd93022000-05-05Martin Nilsson  // Locate internal location resources.
9ac0332002-11-05Anders Johansson  if(has_prefix(file, internal_location))
5839c31999-01-22Marcus Comstedt  {
434bac2000-07-14Andreas Lange  TRACE_ENTER("Magic internal module location", 0);
e351dd1999-11-29Per Hedbor  RoxenModule module;
5839c31999-01-22Marcus Comstedt  string name, rest; function find_internal;
9ac0332002-11-05Anders Johansson  if(2==sscanf(file[strlen(internal_location)..], "%s/%s", name, rest) &&
5839c31999-01-22Marcus Comstedt  (module = find_module(replace(name, "!", "#"))) && (find_internal = module->find_internal)) { #ifdef MODULE_LEVEL_SECURITY if(tmp2 = check_security(find_internal, id, slevel)) if(intp(tmp2)) {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Permission to access module denied.");
5839c31999-01-22Marcus Comstedt  find_internal = 0; } else { TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Request denied.");
9c19002001-02-27Per Hedbor  TIMER_END(internal_magic);
5839c31999-01-22Marcus Comstedt  return tmp2; } #endif
41b77c1999-07-15David Hedbor  if(find_internal)
5839c31999-01-22Marcus Comstedt  {
434bac2000-07-14Andreas Lange  TRACE_ENTER("Calling find_internal()...", find_internal);
4717052001-05-07Per Hedbor  PROF_ENTER("find_internal","location");
5839c31999-01-22Marcus Comstedt  LOCK(find_internal); fid=find_internal( rest, id ); UNLOCK();
02c6642001-08-22Martin Stjernholm  //TRACE_LEAVE(sprintf("find_internal has returned %O", fid)); TRACE_LEAVE("");
4717052001-05-07Per Hedbor  PROF_LEAVE("find_internal","location");
5839c31999-01-22Marcus Comstedt  if(fid) { if(mappingp(fid)) { TRACE_LEAVE(""); TRACE_LEAVE(examine_return_mapping(fid));
9c19002001-02-27Per Hedbor  TIMER_END(internal_magic);
5839c31999-01-22Marcus Comstedt  return fid; } else { #ifdef MODULE_LEVEL_SECURITY int oslevel = slevel;
e280792004-03-03Anders Johansson  array slca; if(slca = security_level_cache[ Roxen.get_owning_module (find_internal) ]) slevel = slca[1];
5910aa2004-02-17Martin Stjernholm  // security_level_cache from
5839c31999-01-22Marcus Comstedt  // check_security id->misc->seclevel = slevel; #endif if(objectp(fid))
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned open filedescriptor. "
5839c31999-01-22Marcus Comstedt #ifdef MODULE_LEVEL_SECURITY +(slevel != oslevel?
434bac2000-07-14Andreas Lange  sprintf(" The security level is now %d.", slevel):"")
5839c31999-01-22Marcus Comstedt #endif
67f60e2000-07-09Martin Nilsson  );
5839c31999-01-22Marcus Comstedt  else
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned directory indicator."
5839c31999-01-22Marcus Comstedt #ifdef MODULE_LEVEL_SECURITY +(oslevel != slevel?
434bac2000-07-14Andreas Lange  sprintf(" The security level is now %d.", slevel):"")
5839c31999-01-22Marcus Comstedt #endif ); } } else TRACE_LEAVE(""); } else TRACE_LEAVE(""); } else TRACE_LEAVE(""); }
9c19002001-02-27Per Hedbor  TIMER_END(internal_magic);
14179b1997-01-29Per Hedbor  } // Well, this just _might_ be somewhat over-optimized, since it is
10c7e11999-12-28Martin Nilsson  // quite unreadable, but, you cannot win them all..
5839c31999-01-22Marcus Comstedt  if(!fid) {
14179b1997-01-29Per Hedbor #ifdef URL_MODULES
f128901997-08-15Henrik Grubbström (Grubba)  // Map URL-modules
9c19002001-02-27Per Hedbor  TIMER_START(url_modules);
517c7e2000-09-30Per Hedbor  foreach(url_module_cache||url_modules(), funp)
41d0f91998-02-20Per Hedbor  {
4717052001-05-07Per Hedbor  PROF_ENTER(Roxen.get_owning_module(funp)->module_name,"url module");
5839c31999-01-22Marcus Comstedt  LOCK(funp);
434bac2000-07-14Andreas Lange  TRACE_ENTER("URL module", funp);
5839c31999-01-22Marcus Comstedt  tmp=funp( id, file ); UNLOCK();
4717052001-05-07Per Hedbor  PROF_LEAVE(Roxen.get_owning_module(funp)->module_name,"url module");
10c7e11999-12-28Martin Nilsson  if(mappingp(tmp))
5839c31999-01-22Marcus Comstedt  { TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
9c19002001-02-27Per Hedbor  TIMER_END(url_modules);
5839c31999-01-22Marcus Comstedt  return tmp; } if(objectp( tmp )) {
a51a902001-11-12Martin Stjernholm  mixed err;
a8f1b32000-01-31Per Hedbor 
6906942004-05-21Henrik Grubbström (Grubba)  id->misc->get_file_nest++;
5839c31999-01-22Marcus Comstedt  err = catch {
6906942004-05-21Henrik Grubbström (Grubba)  if( id->misc->get_file_nest < 20 )
5839c31999-01-22Marcus Comstedt  tmp = (id->conf || this_object())->low_get_file( tmp, no_magic ); else {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Too deep recursion");
5839c31999-01-22Marcus Comstedt  error("Too deep recursion in roxen::get_file() while mapping " +file+".\n"); } };
6906942004-05-21Henrik Grubbström (Grubba)  id->misc->get_file_nest = 0;
5839c31999-01-22Marcus Comstedt  if(err) throw(err); TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
9c19002001-02-27Per Hedbor  TIMER_END(url_modules);
5839c31999-01-22Marcus Comstedt  return tmp; }
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
9c19002001-02-27Per Hedbor  TIMER_END(url_modules);
41d0f91998-02-20Per Hedbor  }
14179b1997-01-29Per Hedbor #endif
c5e0961999-10-04Per Hedbor 
9c19002001-02-27Per Hedbor  TIMER_START(location_modules);
517c7e2000-09-30Per Hedbor  foreach(location_module_cache||location_modules(), tmp)
14179b1997-01-29Per Hedbor  {
5839c31999-01-22Marcus Comstedt  loc = tmp[0];
73f9322004-05-06Martin Stjernholm  if(has_prefix(file, loc))
5839c31999-01-22Marcus Comstedt  {
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Location module [%s] ", loc), tmp[1]);
df8d711998-02-27Per Hedbor #ifdef MODULE_LEVEL_SECURITY
5839c31999-01-22Marcus Comstedt  if(tmp2 = check_security(tmp[1], id, slevel)) if(intp(tmp2)) {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Permission to access module denied.");
5839c31999-01-22Marcus Comstedt  continue; } else { TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Request denied.");
9c19002001-02-27Per Hedbor  TIMER_END(location_modules);
5839c31999-01-22Marcus Comstedt  return tmp2; }
14179b1997-01-29Per Hedbor #endif
7937df2001-05-16Per Hedbor  PROF_ENTER(Roxen.get_owning_module(tmp[1])->module_name,"location");
434bac2000-07-14Andreas Lange  TRACE_ENTER("Calling find_file()...", 0);
5839c31999-01-22Marcus Comstedt  LOCK(tmp[1]); fid=tmp[1]( file[ strlen(loc) .. ] + id->extra_extension, id); UNLOCK();
b8b1072000-03-24Per Hedbor  TRACE_LEAVE("");
7937df2001-05-16Per Hedbor  PROF_LEAVE(Roxen.get_owning_module(tmp[1])->module_name,"location");
5839c31999-01-22Marcus Comstedt  if(fid)
14179b1997-01-29Per Hedbor  {
5839c31999-01-22Marcus Comstedt  id->virtfile = loc;
a8f1b32000-01-31Per Hedbor 
5839c31999-01-22Marcus Comstedt  if(mappingp(fid)) {
fe616a2003-06-10Anders Johansson  TRACE_LEAVE(""); // Location module [...]
5839c31999-01-22Marcus Comstedt  TRACE_LEAVE(examine_return_mapping(fid));
9c19002001-02-27Per Hedbor  TIMER_END(location_modules);
5839c31999-01-22Marcus Comstedt  return fid; } else {
14179b1997-01-29Per Hedbor #ifdef MODULE_LEVEL_SECURITY
5839c31999-01-22Marcus Comstedt  int oslevel = slevel;
e280792004-03-03Anders Johansson  array slca; if(slca = security_level_cache[ Roxen.get_owning_module (tmp[1]) ]) slevel = slca[1];
5910aa2004-02-17Martin Stjernholm  // security_level_cache from
5839c31999-01-22Marcus Comstedt  // check_security id->misc->seclevel = slevel;
14179b1997-01-29Per Hedbor #endif
5839c31999-01-22Marcus Comstedt  if(objectp(fid))
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned open filedescriptor."
41d0f91998-02-20Per Hedbor #ifdef MODULE_LEVEL_SECURITY
5839c31999-01-22Marcus Comstedt  +(slevel != oslevel?
434bac2000-07-14Andreas Lange  sprintf(" The security level is now %d.", slevel):"")
41d0f91998-02-20Per Hedbor #endif
a8f1b32000-01-31Per Hedbor 
67f60e2000-07-09Martin Nilsson  );
5839c31999-01-22Marcus Comstedt  else
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned directory indicator."
41d0f91998-02-20Per Hedbor #ifdef MODULE_LEVEL_SECURITY
5839c31999-01-22Marcus Comstedt  +(oslevel != slevel?
434bac2000-07-14Andreas Lange  sprintf(" The security level is now %d.", slevel):"")
41d0f91998-02-20Per Hedbor #endif
5839c31999-01-22Marcus Comstedt  ); break; } } else TRACE_LEAVE("");
41b77c1999-07-15David Hedbor  } else if(strlen(loc)-1==strlen(file) && file+"/" == loc) {
10c7e11999-12-28Martin Nilsson  // This one is here to allow accesses to /local, even if
5839c31999-01-22Marcus Comstedt  // the mountpoint is /local/. It will slow things down, but...
67f60e2000-07-09Martin Nilsson 
434bac2000-07-14Andreas Lange  TRACE_ENTER("Automatic redirect to location_module.", tmp[1]);
fe616a2003-06-10Anders Johansson  TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
a8f1b32000-01-31Per Hedbor 
41b77c1999-07-15David Hedbor  // Keep query (if any).
fd93022000-05-05Martin Nilsson  // FIXME: Should probably keep config <foo>
dfe0362000-03-19Martin Nilsson  string new_query = Roxen.http_encode_string(id->not_query) + "/" +
41b77c1999-07-15David Hedbor  (id->query?("?"+id->query):"");
fd93022000-05-05Martin Nilsson  new_query=Roxen.add_pre_state(new_query, id->prestate);
a8f1b32000-01-31Per Hedbor 
9c19002001-02-27Per Hedbor  TIMER_END(location_modules);
dfe0362000-03-19Martin Nilsson  return Roxen.http_redirect(new_query, id);
41d0f91998-02-20Per Hedbor  }
14179b1997-01-29Per Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(location_modules);
14179b1997-01-29Per Hedbor  }
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  if(fid == -1) {
41d0f91998-02-20Per Hedbor  if(no_magic) {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("No magic requested. Returning -1.");
41d0f91998-02-20Per Hedbor  return -1; }
9c19002001-02-27Per Hedbor  TIMER_START(directory_module);
14179b1997-01-29Per Hedbor  if(dir_module) {
7937df2001-05-16Per Hedbor  PROF_ENTER(dir_module->module_name,"directory");
14179b1997-01-29Per Hedbor  LOCK(dir_module);
434bac2000-07-14Andreas Lange  TRACE_ENTER("Directory module", dir_module);
14179b1997-01-29Per Hedbor  fid = dir_module->parse_directory(id);
fe616a2003-06-10Anders Johansson  TRACE_LEAVE("");
14179b1997-01-29Per Hedbor  UNLOCK();
7937df2001-05-16Per Hedbor  PROF_LEAVE(dir_module->module_name,"directory");
14179b1997-01-29Per Hedbor  } else
41d0f91998-02-20Per Hedbor  {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("No directory module. Returning 'no such file'");
14179b1997-01-29Per Hedbor  return 0;
41d0f91998-02-20Per Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(directory_module);
10c7e11999-12-28Martin Nilsson  if(mappingp(fid))
41d0f91998-02-20Per Hedbor  {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
41d0f91998-02-20Per Hedbor  return (mapping)fid; }
14179b1997-01-29Per Hedbor  }
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  // Map the file extensions, but only if there is a file...
9c19002001-02-27Per Hedbor  TIMER_START(extension_module);
41b77c1999-07-15David Hedbor  if(objectp(fid) &&
f511c52001-08-31Per Hedbor  (tmp = file_extension_modules(loc = lower_case(Roxen.extension(id->not_query, id)))))
517c7e2000-09-30Per Hedbor  {
14179b1997-01-29Per Hedbor  foreach(tmp, funp) {
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Extension module [%s] ", loc), funp);
14179b1997-01-29Per Hedbor #ifdef MODULE_LEVEL_SECURITY if(tmp=check_security(funp, id, slevel)) if(intp(tmp)) {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Permission to access module denied.");
14179b1997-01-29Per Hedbor  continue; } else
41d0f91998-02-20Per Hedbor  { TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Permission denied");
9c19002001-02-27Per Hedbor  TIMER_END(extension_module);
14179b1997-01-29Per Hedbor  return tmp;
41d0f91998-02-20Per Hedbor  }
14179b1997-01-29Per Hedbor #endif
7937df2001-05-16Per Hedbor  PROF_ENTER(Roxen.get_owning_module(funp)->module_name,"ext");
14179b1997-01-29Per Hedbor  LOCK(funp); tmp=funp(fid, loc, id); UNLOCK();
7937df2001-05-16Per Hedbor  PROF_LEAVE(Roxen.get_owning_module(funp)->module_name,"ext");
14179b1997-01-29Per Hedbor  if(tmp) { if(!objectp(tmp))
41d0f91998-02-20Per Hedbor  { TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
9c19002001-02-27Per Hedbor  TIMER_END(extension_module);
14179b1997-01-29Per Hedbor  return tmp;
41d0f91998-02-20Per Hedbor  }
cd92872000-08-15Johan Sundström  if(fid && tmp != fid)
41b77c1999-07-15David Hedbor  destruct(fid);
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned new open file");
14179b1997-01-29Per Hedbor  fid = tmp; break;
41d0f91998-02-20Per Hedbor  } else TRACE_LEAVE("");
14179b1997-01-29Per Hedbor  }
41b77c1999-07-15David Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(extension_module);
fd93022000-05-05Martin Nilsson 
14179b1997-01-29Per Hedbor  if(objectp(fid)) {
9c19002001-02-27Per Hedbor  TIMER_START(content_type_module);
41b77c1999-07-15David Hedbor  if(stringp(id->extension)) {
14179b1997-01-29Per Hedbor  id->not_query += id->extension;
f511c52001-08-31Per Hedbor  loc = lower_case(Roxen.extension(id->not_query, id));
41b77c1999-07-15David Hedbor  }
434bac2000-07-14Andreas Lange  TRACE_ENTER("Content-type mapping module", types_module);
41b77c1999-07-15David Hedbor  tmp=type_from_filename(id->not_query, 1, loc);
3d94582000-07-31Martin Nilsson  TRACE_LEAVE(tmp?sprintf("Returned type %s %s.", tmp[0], tmp[1]||"")
434bac2000-07-14Andreas Lange  : "Missing type.");
14179b1997-01-29Per Hedbor  if(tmp)
41d0f91998-02-20Per Hedbor  { TRACE_LEAVE("");
9c19002001-02-27Per Hedbor  TIMER_END(content_type_module);
14179b1997-01-29Per Hedbor  return ([ "file":fid, "type":tmp[0], "encoding":tmp[1] ]);
10c7e11999-12-28Martin Nilsson  }
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
9c19002001-02-27Per Hedbor  TIMER_END(content_type_module);
14179b1997-01-29Per Hedbor  return ([ "file":fid, ]); }
9c19002001-02-27Per Hedbor 
41d0f91998-02-20Per Hedbor  if(!fid)
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned 'no such file'.");
41d0f91998-02-20Per Hedbor  else
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
14179b1997-01-29Per Hedbor  return fid; }
6877622004-04-19Martin Stjernholm #define TRY_FIRST_MODULES(FILE, RECURSE_CALL) do { \ TIMER_START(first_modules); \ foreach(first_module_cache||first_modules(), function funp) \ { \ TRACE_ENTER ("First try module", funp); \ if(FILE = funp( id )) { \ TRACE_LEAVE ("Got response"); \ break; \ } \ TRACE_LEAVE ("No response"); \ if(id->conf != this_object()) { \ TRACE_ENTER (sprintf ("Configuration changed to %O - " \ "redirecting", id->conf), 0); \ TRACE_LEAVE (""); \ TIMER_END (first_modules); \ TIMER_END (handle_request); \ return id->conf->RECURSE_CALL; \ } \ } \ TIMER_END(first_modules); \ } while (0) #define TRY_LAST_MODULES(FILE, RECURSE_CALL) do { \ mixed ret; \ TIMER_START(last_modules); \ foreach(last_module_cache||last_modules(), function funp) { \ TRACE_ENTER ("Last try module", funp); \ if(ret = funp(id)) { \ if (ret == 1) { \ TRACE_LEAVE ("Request rewritten - try again"); \ TIMER_END(last_modules); \ TIMER_END(handle_request); \ return RECURSE_CALL; \ } \ TRACE_LEAVE ("Got response"); \ break; \ } \ TRACE_LEAVE ("No response"); \ } \ FILE = ret; \ TIMER_END(last_modules); \ } while (0) mixed handle_request( RequestID id, void|int recurse_count)
c7a5f01999-02-16Per Hedbor { mixed file;
10c7e11999-12-28Martin Nilsson  REQUEST_WERR("handle_request()");
6877622004-04-19Martin Stjernholm  if (recurse_count > 50) { TRACE_ENTER ("Looped " + recurse_count + " times in internal redirects - giving up", 0); TRACE_LEAVE (""); return 0;
c7a5f01999-02-16Per Hedbor  }
6877622004-04-19Martin Stjernholm  TIMER_START(handle_request); TRY_FIRST_MODULES (file, handle_request (id, recurse_count + 1));
fd8b151999-05-19David Hedbor  if(!mappingp(file) && !mappingp(file = get_file(id)))
6877622004-04-19Martin Stjernholm  TRY_LAST_MODULES (file, handle_request(id, recurse_count + 1));
9c19002001-02-27Per Hedbor  TIMER_END(handle_request);
6877622004-04-19Martin Stjernholm 
10c7e11999-12-28Martin Nilsson  REQUEST_WERR("handle_request(): Done");
9c19002001-02-27Per Hedbor  MERGE_TIMERS(roxen);
c7a5f01999-02-16Per Hedbor  return file; }
9a0d4b2004-04-20Henrik Grubbström (Grubba) mapping|int get_file(RequestID id, int|void no_magic, int|void internal_get)
cd92872000-08-15Johan Sundström //! Return a result mapping for the id object at hand, mapping all //! modules, including the filter modules. This function is mostly a
09a0682004-04-20Henrik Grubbström (Grubba) //! wrapper for @[low_get_file()].
14179b1997-01-29Per Hedbor {
9c19002001-02-27Per Hedbor  TIMER_START(get_file);
576c112000-03-07Martin Stjernholm  int orig_internal_get = id->misc->internal_get; id->misc->internal_get = internal_get;
483b062002-05-16Stefan Wallström  RequestID root_id = id->root_id || id; root_id->misc->_request_depth++; if(sub_req_limit && root_id->misc->_request_depth > sub_req_limit)
9ac0332002-11-05Anders Johansson  error("Subrequest limit reached. (Possibly an insertion loop.)");
576c112000-03-07Martin Stjernholm 
fd93022000-05-05Martin Nilsson  mapping|int res; mapping res2;
14179b1997-01-29Per Hedbor  function tmp; res = low_get_file(id, no_magic);
9c19002001-02-27Per Hedbor  TIMER_END(get_file);
fd93022000-05-05Martin Nilsson 
14179b1997-01-29Per Hedbor  // finally map all filter type modules. // Filter modules are like TYPE_LAST modules, but they get called // for _all_ files.
9c19002001-02-27Per Hedbor  TIMER_START(filter_modules);
517c7e2000-09-30Per Hedbor  foreach(filter_module_cache||filter_modules(), tmp)
41d0f91998-02-20Per Hedbor  {
434bac2000-07-14Andreas Lange  TRACE_ENTER("Filter module", tmp);
4717052001-05-07Per Hedbor  PROF_ENTER(Roxen.get_owning_module(tmp)->module_name,"filter");
14179b1997-01-29Per Hedbor  if(res2=tmp(res,id)) {
8b815d2004-04-20Martin Stjernholm  if(mappingp(res) && res->file && (res2->file != res->file))
14179b1997-01-29Per Hedbor  destruct(res->file);
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Rewrote result.");
14179b1997-01-29Per Hedbor  res=res2;
41d0f91998-02-20Per Hedbor  } else TRACE_LEAVE("");
4717052001-05-07Per Hedbor  PROF_LEAVE(Roxen.get_owning_module(tmp)->module_name,"filter");
41d0f91998-02-20Per Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(filter_modules);
576c112000-03-07Martin Stjernholm 
483b062002-05-16Stefan Wallström  root_id->misc->_request_depth--;
576c112000-03-07Martin Stjernholm  id->misc->internal_get = orig_internal_get;
14179b1997-01-29Per Hedbor  return res; }
9a8a152000-09-25Per Hedbor array(string) find_dir(string file, RequestID id, void|int(0..1) verbose)
14179b1997-01-29Per Hedbor {
fd93022000-05-05Martin Nilsson  array dir;
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("List directory %O.", file), 0);
10c7e11999-12-28Martin Nilsson 
db43d12000-11-24Martin Stjernholm  if(!sizeof (file) || file[0] != '/')
1935351997-04-28Henrik Grubbström (Grubba)  file = "/" + file;
f128901997-08-15Henrik Grubbström (Grubba) #ifdef URL_MODULES
fc0e5d1997-08-26Henrik Grubbström (Grubba) #ifdef THREADS
3e3bab2001-01-19Per Hedbor  Thread.MutexKey key;
fc0e5d1997-08-26Henrik Grubbström (Grubba) #endif
f128901997-08-15Henrik Grubbström (Grubba)  // Map URL-modules
517c7e2000-09-30Per Hedbor  foreach(url_modules(), function funp)
f128901997-08-15Henrik Grubbström (Grubba)  { string of = id->not_query; id->not_query = file; LOCK(funp);
434bac2000-07-14Andreas Lange  TRACE_ENTER("URL module", funp);
3e3bab2001-01-19Per Hedbor  mixed remap=funp( id, file );
f128901997-08-15Henrik Grubbström (Grubba)  UNLOCK();
fd93022000-05-05Martin Nilsson  if(mappingp( remap ))
f128901997-08-15Henrik Grubbström (Grubba)  { id->not_query=of;
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned 'No thanks'.");
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
f128901997-08-15Henrik Grubbström (Grubba)  return 0; }
fd93022000-05-05Martin Nilsson  if(objectp( remap ))
f128901997-08-15Henrik Grubbström (Grubba)  {
a51a902001-11-12Martin Stjernholm  mixed err;
6906942004-05-21Henrik Grubbström (Grubba)  id->misc->find_dir_nest++;
10c7e11999-12-28Martin Nilsson 
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Recursing");
f128901997-08-15Henrik Grubbström (Grubba)  file = id->not_query; err = catch {
6906942004-05-21Henrik Grubbström (Grubba)  if( id->misc->find_dir_nest < 20 )
fd93022000-05-05Martin Nilsson  dir = (id->conf || this_object())->find_dir( file, id );
f128901997-08-15Henrik Grubbström (Grubba)  else error("Too deep recursion in roxen::find_dir() while mapping " +file+".\n"); };
6906942004-05-21Henrik Grubbström (Grubba)  id->misc->find_dir_nest = 0;
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
f128901997-08-15Henrik Grubbström (Grubba)  if(err) throw(err);
fd93022000-05-05Martin Nilsson  return dir;
f128901997-08-15Henrik Grubbström (Grubba)  } id->not_query=of; }
a86c6c1997-09-22Henrik Grubbström (Grubba) #endif /* URL_MODULES */
f128901997-08-15Henrik Grubbström (Grubba) 
3e3bab2001-01-19Per Hedbor  array | mapping d;
e927de2000-05-06Martin Nilsson  array(string) locks=({});
3e3bab2001-01-19Per Hedbor  RoxenModule mod;
e927de2000-05-06Martin Nilsson  string loc;
517c7e2000-09-30Per Hedbor  foreach(location_modules(), array tmp)
14179b1997-01-29Per Hedbor  { loc = tmp[0];
a476711997-10-20Henrik Grubbström (Grubba)  if(!search(file, loc)) { /* file == loc + subpath */
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Location module [%s] ", loc), tmp[1]);
a78a591997-04-28Henrik Grubbström (Grubba) #ifdef MODULE_LEVEL_SECURITY
41d0f91998-02-20Per Hedbor  if(check_security(tmp[1], id)) {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Permission denied");
41d0f91998-02-20Per Hedbor  continue; }
a78a591997-04-28Henrik Grubbström (Grubba) #endif
e927de2000-05-06Martin Nilsson  mod=function_object(tmp[1]); if(d=mod->find_dir(file[strlen(loc)..], id))
41d0f91998-02-20Per Hedbor  {
29a8071998-08-21David Hedbor  if(mappingp(d)) {
10c7e11999-12-28Martin Nilsson  if(d->files) {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Got exclusive directory."); TRACE_LEAVE(sprintf("Returning list of %d files.", sizeof(d->files)));
fd93022000-05-05Martin Nilsson  return d->files;
29a8071998-08-21David Hedbor  } else TRACE_LEAVE(""); } else {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Got files.");
e927de2000-05-06Martin Nilsson  if(!dir) dir=({ });
29a8071998-08-21David Hedbor  dir |= d; }
e927de2000-05-06Martin Nilsson  } else { if(verbose && mod->list_lock_files) locks |= mod->list_lock_files();
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
e927de2000-05-06Martin Nilsson  }
a476711997-10-20Henrik Grubbström (Grubba)  } else if((search(loc, file)==0) && (loc[strlen(file)-1]=='/') && (loc[0]==loc[-1]) && (loc[-1]=='/') &&
6c67c81998-02-28Johan Schön  (function_object(tmp[1])->stat_file(".", id))) {
a476711997-10-20Henrik Grubbström (Grubba)  /* loc == file + "/" + subpath + "/"
24fa081998-02-28Henrik Grubbström (Grubba)  * and stat_file(".") returns non-zero.
a476711997-10-20Henrik Grubbström (Grubba)  */
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Location module [%s] ", loc), tmp[1]);
a476711997-10-20Henrik Grubbström (Grubba)  loc=loc[strlen(file)..]; sscanf(loc, "%s/", loc);
df40452000-06-19Henrik Grubbström (Grubba)  if (dir) { dir |= ({ loc }); } else { dir = ({ loc }); }
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Added module mountpoint.");
14179b1997-01-29Per Hedbor  } }
e927de2000-05-06Martin Nilsson  if(!dir) return verbose ? ({0})+locks : ([])[0];
14179b1997-01-29Per Hedbor  if(sizeof(dir))
41d0f91998-02-20Per Hedbor  {
434bac2000-07-14Andreas Lange  TRACE_LEAVE(sprintf("Returning list of %d files.", sizeof(dir)));
14179b1997-01-29Per Hedbor  return dir;
10c7e11999-12-28Martin Nilsson  }
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning 'No such directory'.");
fd93022000-05-05Martin Nilsson  return 0;
14179b1997-01-29Per Hedbor }
10c7e11999-12-28Martin Nilsson // Stat a virtual file.
14179b1997-01-29Per Hedbor 
9a8a152000-09-25Per Hedbor array(int)|Stat stat_file(string file, RequestID id)
14179b1997-01-29Per Hedbor {
1f4a6c2000-08-28Per Hedbor  mixed s, tmp;
c5e0961999-10-04Per Hedbor #ifdef THREADS
3e3bab2001-01-19Per Hedbor  Thread.MutexKey key;
c5e0961999-10-04Per Hedbor #endif
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Stat file %O.", file), 0);
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  file=replace(file, "//", "/"); // "//" is really "/" here...
f128901997-08-15Henrik Grubbström (Grubba)  #ifdef URL_MODULES // Map URL-modules
6906942004-05-21Henrik Grubbström (Grubba)  string of = id->not_query; id->not_query = file; foreach(url_module_cache||url_modules(), function funp)
f128901997-08-15Henrik Grubbström (Grubba)  {
434bac2000-07-14Andreas Lange  TRACE_ENTER("URL module", funp);
f128901997-08-15Henrik Grubbström (Grubba)  LOCK(funp); tmp=funp( id, file ); UNLOCK();
6906942004-05-21Henrik Grubbström (Grubba)  if (tmp) { if(mappingp( tmp )) { id->not_query = of; TRACE_LEAVE(""); TRACE_LEAVE("Returned 'No thanks'."); return 0; } if(objectp( tmp )) { mixed err; id->misc->stat_file_nest++; id->not_query = of; TRACE_LEAVE("Recursing"); err = catch { if( id->misc->stat_file_nest < 20 ) tmp = (id->conf || this_object())->stat_file( file, id ); else error("Too deep recursion in roxen::stat_file() while mapping " +file+".\n"); }; id->misc->stat_file_nest = 0; if(err) throw(err); TRACE_LEAVE(""); TRACE_LEAVE("Returning data"); return tmp; }
f128901997-08-15Henrik Grubbström (Grubba)  }
8fd51f1998-03-01Per Hedbor  TRACE_LEAVE("");
f128901997-08-15Henrik Grubbström (Grubba)  }
6906942004-05-21Henrik Grubbström (Grubba)  id->not_query = of;
f128901997-08-15Henrik Grubbström (Grubba) #endif
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  // Map location-modules.
6906942004-05-21Henrik Grubbström (Grubba)  foreach(location_module_cache||location_modules(), [string loc, function fun]) {
14179b1997-01-29Per Hedbor  if((file == loc) || ((file+"/")==loc))
41d0f91998-02-20Per Hedbor  {
6906942004-05-21Henrik Grubbström (Grubba)  TRACE_ENTER(sprintf("Location module [%s] ", loc), fun);
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Exact match.");
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
6906942004-05-21Henrik Grubbström (Grubba)  return Stdio.Stat(({ 0775, -3, 0, 0, 0, 0, 0 }));
41d0f91998-02-20Per Hedbor  }
6906942004-05-21Henrik Grubbström (Grubba)  if(has_prefix(file, loc))
14179b1997-01-29Per Hedbor  {
6906942004-05-21Henrik Grubbström (Grubba)  TRACE_ENTER(sprintf("Location module [%s] ", loc), fun);
a78a591997-04-28Henrik Grubbström (Grubba) #ifdef MODULE_LEVEL_SECURITY
6906942004-05-21Henrik Grubbström (Grubba)  if(check_security(fun, id)) {
8fd51f1998-03-01Per Hedbor  TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Permission denied");
41d0f91998-02-20Per Hedbor  continue; }
a78a591997-04-28Henrik Grubbström (Grubba) #endif
6906942004-05-21Henrik Grubbström (Grubba)  if(s=function_object(fun)->stat_file(file[strlen(loc)..], id))
41d0f91998-02-20Per Hedbor  { TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Stat ok.");
14179b1997-01-29Per Hedbor  return s;
41d0f91998-02-20Per Hedbor  } TRACE_LEAVE("");
14179b1997-01-29Per Hedbor  } }
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned 'no such file'.");
14179b1997-01-29Per Hedbor }
73ce3d2000-12-11Per Hedbor mapping error_file( RequestID id ) { string data = query("ZNoSuchFile"); NOCACHE();
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 2.1
73ce3d2000-12-11Per Hedbor  data = replace(data,({"$File", "$Me"}),
1493442000-12-17Henrik Grubbström (Grubba)  ({"&page.virtfile;", "&roxen.server;"}));
73ce3d2000-12-11Per Hedbor #endif
1371e02001-06-22Martin Nilsson  mapping res = Roxen.http_rxml_answer( data, id, 0, "text/html" ); res->error = 404; return res;
73ce3d2000-12-11Per Hedbor }
e8790b1998-02-19Per Hedbor // this is not as trivial as it sounds. Consider gtext. :-)
6877622004-04-19Martin Stjernholm array open_file(string fname, string mode, RequestID id, void|int internal_get, void|int recurse_count)
e8790b1998-02-19Per Hedbor {
6877622004-04-19Martin Stjernholm  mapping|int(0..1) file; string oq = id->not_query;
517c7e2000-09-30Per Hedbor  if( id->conf && (id->conf != this_object()) )
6877622004-04-19Martin Stjernholm  return id->conf->open_file( fname, mode, id, internal_get, recurse_count );
517c7e2000-09-30Per Hedbor 
6877622004-04-19Martin Stjernholm  if (recurse_count > 50) { TRACE_ENTER ("Looped " + recurse_count + " times in internal redirects - giving up", 0); TRACE_LEAVE (""); }
cd7ea41998-12-14Peter Bortas 
6877622004-04-19Martin Stjernholm  else { Configuration oc = id->conf; id->not_query = fname; TRY_FIRST_MODULES (file, open_file (fname, mode, id, internal_get, recurse_count + 1)); fname = id->not_query;
c7a5f01999-02-16Per Hedbor 
6877622004-04-19Martin Stjernholm  if(search(mode, "R")!=-1) // raw (as in not parsed..)
e8790b1998-02-19Per Hedbor  {
6877622004-04-19Martin Stjernholm  string f; mode -= "R"; if(f = real_file(fname, id)) { // report_debug("opening "+fname+" in raw mode.\n"); return ({ open(f, mode), ([]) }); } // return ({ 0, (["error":302]) });
e8790b1998-02-19Per Hedbor  }
6877622004-04-19Martin Stjernholm  if(mode!="r") { id->not_query = oq; return ({ 0, (["error":501, "data":"Not implemented." ]) });
41d0f91998-02-20Per Hedbor  }
e8790b1998-02-19Per Hedbor  if(!file) {
517c7e2000-09-30Per Hedbor  file = get_file( id, 0, internal_get );
6877622004-04-19Martin Stjernholm  if(!file) TRY_LAST_MODULES (file, open_file (id->not_query, mode, id, internal_get, recurse_count + 1));
e8790b1998-02-19Per Hedbor  }
6877622004-04-19Martin Stjernholm  }
e8790b1998-02-19Per Hedbor 
6877622004-04-19Martin Stjernholm  if(!mappingp(file)) { if(id->misc->error_code) file = Roxen.http_low_answer(id->misc->error_code, "Failed" ); else if(id->method!="GET"&&id->method != "HEAD"&&id->method!="POST") file = Roxen.http_low_answer(501, "Not implemented."); else file = error_file( id );
e8790b1998-02-19Per Hedbor 
6877622004-04-19Martin Stjernholm  id->not_query = oq;
10c7e11999-12-28Martin Nilsson 
6877622004-04-19Martin Stjernholm  return ({ 0, file }); }
e8790b1998-02-19Per Hedbor 
6877622004-04-19Martin Stjernholm  if( file->data ) { file->file = StringFile(file->data); m_delete(file, "data");
e8790b1998-02-19Per Hedbor  } id->not_query = oq;
7db9292004-05-18Anders Johansson  return ({ file->file || StringFile(""), file });
e8790b1998-02-19Per Hedbor }
9a8a152000-09-25Per Hedbor mapping(string:array(mixed)) find_dir_stat(string file, RequestID id)
a86c6c1997-09-22Henrik Grubbström (Grubba) { string loc;
a476711997-10-20Henrik Grubbström (Grubba)  mapping(string:array(mixed)) dir = ([]); mixed d, tmp;
a86c6c1997-09-22Henrik Grubbström (Grubba) 
c7a5f01999-02-16Per Hedbor 
a86c6c1997-09-22Henrik Grubbström (Grubba)  file=replace(file, "//", "/");
10c7e11999-12-28Martin Nilsson 
db43d12000-11-24Martin Stjernholm  if(!sizeof (file) || file[0] != '/')
a86c6c1997-09-22Henrik Grubbström (Grubba)  file = "/" + file;
ae60b61998-05-23Henrik Grubbström (Grubba)  // FIXME: Should I append a "/" to file if missing?
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Request for directory and stat's \"%s\".", file), 0);
ae60b61998-05-23Henrik Grubbström (Grubba) 
a86c6c1997-09-22Henrik Grubbström (Grubba) #ifdef URL_MODULES #ifdef THREADS
3e3bab2001-01-19Per Hedbor  Thread.MutexKey key;
a86c6c1997-09-22Henrik Grubbström (Grubba) #endif // Map URL-modules
517c7e2000-09-30Per Hedbor  foreach(url_modules(), function funp)
a86c6c1997-09-22Henrik Grubbström (Grubba)  { string of = id->not_query; id->not_query = file; LOCK(funp);
434bac2000-07-14Andreas Lange  TRACE_ENTER("URL module", funp);
a86c6c1997-09-22Henrik Grubbström (Grubba)  tmp=funp( id, file ); UNLOCK(); if(mappingp( tmp )) { id->not_query=of;
3510fb1997-11-09Henrik Grubbström (Grubba) #ifdef MODULE_DEBUG
91d3c32001-03-12Martin Nilsson  report_debug("conf->find_dir_stat(\"%s\"): url_module returned mapping:%O\n", file, tmp);
3510fb1997-11-09Henrik Grubbström (Grubba) #endif /* MODULE_DEBUG */
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned mapping."+sprintf("%O", tmp));
07014c1999-05-24Per Hedbor  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  return 0; } if(objectp( tmp )) {
a51a902001-11-12Martin Stjernholm  mixed err;
6906942004-05-21Henrik Grubbström (Grubba)  id->misc->find_dir_stat_nest++;
10c7e11999-12-28Martin Nilsson 
a86c6c1997-09-22Henrik Grubbström (Grubba)  file = id->not_query; err = catch {
6906942004-05-21Henrik Grubbström (Grubba)  if( id->misc->find_dir_stat_nest < 20 )
a86c6c1997-09-22Henrik Grubbström (Grubba)  tmp = (id->conf || this_object())->find_dir_stat( file, id );
ae60b61998-05-23Henrik Grubbström (Grubba)  else {
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Too deep recursion");
a86c6c1997-09-22Henrik Grubbström (Grubba)  error("Too deep recursion in roxen::find_dir_stat() while mapping " +file+".\n");
ae60b61998-05-23Henrik Grubbström (Grubba)  }
a86c6c1997-09-22Henrik Grubbström (Grubba)  };
6906942004-05-21Henrik Grubbström (Grubba)  id->misc->find_dir_stat_nest = 0;
a86c6c1997-09-22Henrik Grubbström (Grubba)  if(err) throw(err);
3510fb1997-11-09Henrik Grubbström (Grubba) #ifdef MODULE_DEBUG
91d3c32001-03-12Martin Nilsson  report_debug("conf->find_dir_stat(\"%s\"): url_module returned object:\n", file);
3510fb1997-11-09Henrik Grubbström (Grubba) #endif /* MODULE_DEBUG */
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned object."); TRACE_LEAVE("Returning it.");
ae60b61998-05-23Henrik Grubbström (Grubba)  return tmp; // FIXME: Return 0 instead?
a86c6c1997-09-22Henrik Grubbström (Grubba)  } id->not_query=of;
ae60b61998-05-23Henrik Grubbström (Grubba)  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  } #endif /* URL_MODULES */
517c7e2000-09-30Per Hedbor  foreach(location_modules(), tmp)
a86c6c1997-09-22Henrik Grubbström (Grubba)  { loc = tmp[0];
a476711997-10-20Henrik Grubbström (Grubba) 
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Location module [%s] ", loc), 0);
a476711997-10-20Henrik Grubbström (Grubba)  /* Note that only new entries are added. */
a86c6c1997-09-22Henrik Grubbström (Grubba)  if(!search(file, loc)) {
a476711997-10-20Henrik Grubbström (Grubba)  /* file == loc + subpath */
a86c6c1997-09-22Henrik Grubbström (Grubba) #ifdef MODULE_LEVEL_SECURITY
8b44de2003-10-07Anders Johansson  if(check_security(tmp[1], id)) { TRACE_LEAVE("Security check failed."); continue; }
a86c6c1997-09-22Henrik Grubbström (Grubba) #endif
e351dd1999-11-29Per Hedbor  RoxenModule c = function_object(tmp[1]);
a86c6c1997-09-22Henrik Grubbström (Grubba)  string f = file[strlen(loc)..]; if (c->find_dir_stat) {
434bac2000-07-14Andreas Lange  TRACE_ENTER("Has find_dir_stat().", 0);
a86c6c1997-09-22Henrik Grubbström (Grubba)  if (d = c->find_dir_stat(f, id)) {
434bac2000-07-14Andreas Lange  TRACE_ENTER("Returned mapping."+sprintf("%O", d), c);
a476711997-10-20Henrik Grubbström (Grubba)  dir = d | dir;
ae60b61998-05-23Henrik Grubbström (Grubba)  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  }
ae60b61998-05-23Henrik Grubbström (Grubba)  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  } else if(d = c->find_dir(f, id)) {
434bac2000-07-14Andreas Lange  TRACE_ENTER("Returned array.", 0);
10c7e11999-12-28Martin Nilsson  dir = mkmapping(d, Array.map(d, lambda(string fn)
e351dd1999-11-29Per Hedbor  { return c->stat_file(f + fn, id); })) | dir;
ae60b61998-05-23Henrik Grubbström (Grubba)  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  }
a476711997-10-20Henrik Grubbström (Grubba)  } else if(search(loc, file)==0 && loc[strlen(file)-1]=='/' && (loc[0]==loc[-1]) && loc[-1]=='/' &&
8935ad1998-03-30Johan Schön  (function_object(tmp[1])->stat_file(".", id))) {
a476711997-10-20Henrik Grubbström (Grubba)  /* loc == file + "/" + subpath + "/"
8935ad1998-03-30Johan Schön  * and stat_file(".") returns non-zero.
a476711997-10-20Henrik Grubbström (Grubba)  */
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("The file %O is on the path to the mountpoint %O.",
67f60e2000-07-09Martin Nilsson  file, loc), 0);
a476711997-10-20Henrik Grubbström (Grubba)  loc=loc[strlen(file)..]; sscanf(loc, "%s/", loc); if (!dir[loc]) {
cd92872000-08-15Johan Sundström  dir[loc] = ({ 0775, -3, 0, 0, 0, 0, 0 });
a86c6c1997-09-22Henrik Grubbström (Grubba)  }
ae60b61998-05-23Henrik Grubbström (Grubba)  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  }
ae60b61998-05-23Henrik Grubbström (Grubba)  TRACE_LEAVE("");
a86c6c1997-09-22Henrik Grubbström (Grubba)  } if(sizeof(dir)) return dir; }
14179b1997-01-29Per Hedbor  // Access a virtual file?
9a8a152000-09-25Per Hedbor array access(string file, RequestID id)
14179b1997-01-29Per Hedbor { string loc; array s, tmp;
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  file=replace(file, "//", "/"); // "//" is really "/" here...
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  // Map location-modules.
517c7e2000-09-30Per Hedbor  foreach(location_modules(), tmp)
14179b1997-01-29Per Hedbor  { loc = tmp[0];
4770421999-11-22Henrik Grubbström (Grubba)  if((file+"/")==loc) { #ifdef MODULE_LEVEL_SECURITY if(check_security(tmp[1], id)) continue; #endif if(s=function_object(tmp[1])->access("", id)) return s; } else if(!search(file, loc)) {
14179b1997-01-29Per Hedbor #ifdef MODULE_LEVEL_SECURITY if(check_security(tmp[1], id)) continue; #endif if(s=function_object(tmp[1])->access(file[strlen(loc)..], id)) return s; } }
4770421999-11-22Henrik Grubbström (Grubba)  return 0;
14179b1997-01-29Per Hedbor }
9a8a152000-09-25Per Hedbor string real_file(string file, RequestID id)
9fd8092000-08-08Johan Sundström //! Return the _real_ filename of a virtual file, if any.
14179b1997-01-29Per Hedbor { string loc; string s; array tmp; file=replace(file, "//", "/"); // "//" is really "/" here...
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  if(!id) error("No id passed to real_file"); // Map location-modules.
517c7e2000-09-30Per Hedbor  foreach(location_modules(), tmp)
14179b1997-01-29Per Hedbor  { loc = tmp[0];
10c7e11999-12-28Martin Nilsson  if(!search(file, loc))
14179b1997-01-29Per Hedbor  { #ifdef MODULE_LEVEL_SECURITY if(check_security(tmp[1], id)) continue; #endif
c5e0961999-10-04Per Hedbor  if(s=function_object(tmp[1])->real_file(file[strlen(loc)..], id))
14179b1997-01-29Per Hedbor  return s; } } }
7424772002-11-05Anders Johansson array(int)|Stat try_stat_file(string s, RequestID id, int|void not_internal) { RequestID fake_id; array(int)|Stat res; if(!objectp(id)) error("No ID passed to 'try_stat_file'\n"); // id->misc->common is here for compatibility; it's better to use // id->root_id->misc. if ( !id->misc ) id->misc = ([]); if ( !id->misc->common ) id->misc->common = ([]); fake_id = id->clone_me(); fake_id->misc->common = id->misc->common; fake_id->misc->internal_get = !not_internal; fake_id->conf = this_object(); if (fake_id->scan_for_query) // FIXME: If we're using e.g. ftp this doesn't exist. But the // right solution might be that clone_me() in an ftp id object // returns a vanilla (i.e. http) id instead when this function is // used. s = fake_id->scan_for_query (s); s = Roxen.fix_relative (s, id); fake_id->raw_url = s; fake_id->not_query = s; fake_id->method = "GET"; res = stat_file(fake_id->not_query, fake_id); destruct (fake_id); return res; }
829e8c2004-04-13Martin Stjernholm static RequestID make_fake_id (string s, RequestID id)
14179b1997-01-29Per Hedbor {
e351dd1999-11-29Per Hedbor  RequestID fake_id;
14179b1997-01-29Per Hedbor 
9644732001-11-27Martin Stjernholm  // id->misc->common is here for compatibility; it's better to use // id->root_id->misc. if ( !id->misc->common ) id->misc->common = ([]);
e351dd1999-11-29Per Hedbor  fake_id = id->clone_me();
10c7e11999-12-28Martin Nilsson 
9644732001-11-27Martin Stjernholm  fake_id->misc->common = id->misc->common;
c8ff272002-09-20Anders Johansson  fake_id->conf = this_object();
e351dd1999-11-29Per Hedbor 
4e0a532000-03-20Martin Stjernholm  if (fake_id->scan_for_query)
c65dbe2001-05-03Per Hedbor  // FIXME: If we're using e.g. ftp this doesn't exist. But the // right solution might be that clone_me() in an ftp id object // returns a vanilla (i.e. http) id instead when this function is // used.
4e0a532000-03-20Martin Stjernholm  s = fake_id->scan_for_query (s);
c65dbe2001-05-03Per Hedbor  s = Roxen.fix_relative (s, id);
14179b1997-01-29Per Hedbor  fake_id->raw_url=s; fake_id->not_query=s;
829e8c2004-04-13Martin Stjernholm  return fake_id; } int|string try_get_file(string s, RequestID id, int|void stat_only, int|void nocache, int|void not_internal, mapping|void result_mapping) //! Convenience function used in quite a lot of modules. Tries to read //! a file into memory, and then returns the resulting string. //! //! NOTE: A 'file' can be a cgi script, which will be executed, //! resulting in a horrible delay. //! //! Unless the not_internal flag is set, this tries to get an external //! or internal file. Here "internal" means a file that never should be //! sent directly as a request response. E.g. an internal redirect to a //! different file is still considered "external" since its contents is //! sent directly to the client. Internal requests are recognized by //! the id->misc->internal_get flag being non-zero. { string res; RequestID fake_id = make_fake_id (s, id); mapping m; fake_id->misc->internal_get = !not_internal;
7a41502001-08-30Henrik Grubbström (Grubba)  fake_id->method = "GET";
14179b1997-01-29Per Hedbor 
a878e22004-04-19Martin Stjernholm  array a = open_file( fake_id->not_query, "r", fake_id, !not_internal );
7db9292004-05-18Anders Johansson  m = a[1]; if (result_mapping) foreach(indices(m), string i) result_mapping[i] = m[i]; if(a[0]) {
829e8c2004-04-13Martin Stjernholm  m->file = a[0]; } else { destruct (fake_id); return 0;
c927a02000-03-18Martin Stjernholm  }
a59fc92000-08-16Per Hedbor  CACHE( fake_id->misc->cacheable );
c927a02000-03-18Martin Stjernholm  destruct (fake_id);
889d031999-10-04Per Hedbor 
96d86e2001-01-29Per Hedbor  // Allow 2* and 3* error codes, not only a few specific ones. if (!(< 0,2,3 >)[m->error/100]) return 0;
10c7e11999-12-28Martin Nilsson 
829e8c2004-04-13Martin Stjernholm  if(stat_only) return 1;
3510fb1997-11-09Henrik Grubbström (Grubba) 
10c7e11999-12-28Martin Nilsson  if(m->data)
a22f6f1999-05-12Per Hedbor  res = m->data;
10c7e11999-12-28Martin Nilsson  else
a22f6f1999-05-12Per Hedbor  res="";
14179b1997-01-29Per Hedbor  m->data = 0;
10c7e11999-12-28Martin Nilsson 
4cb2212000-05-22Per Hedbor  if( objectp(m->file) )
14179b1997-01-29Per Hedbor  {
3a4d7e1997-09-03Per Hedbor  res += m->file->read();
2c66592001-09-06Henrik Grubbström (Grubba)  if (m->file) { // Some wrappers may destruct themselves in read()... destruct(m->file); }
14179b1997-01-29Per Hedbor  m->file = 0; }
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor  if(m->raw) { res -= "\r"; if(!sscanf(res, "%*s\n\n%s", res)) sscanf(res, "%*s\n%s", res); } return res; }
829e8c2004-04-13Martin Stjernholm mapping(string:string) try_get_headers(string s, RequestID id, int|void not_internal) //! Like @[try_get_file] but performs a HEAD request and only returns //! the response headers. Note that the returned headers are as they //! would be in a formatted response by the http protocol module, //! which is completely different from a response mapping. { RequestID fake_id = make_fake_id (s, id); mapping m; fake_id->misc->internal_get = !not_internal; fake_id->method = "HEAD"; array a = open_file( s, "r", fake_id, !not_internal ); if(a && a[1]) { if (a[0]) a[0]->close(); m = a[1]; } else { destruct (fake_id); return 0; } CACHE( fake_id->misc->cacheable ); if (!m->raw) m = fake_id->make_response_headers (m); else { Roxen.HeaderParser hp = Roxen.HeaderParser(); array res; if(m->data) res = hp->feed (m->data); if (!res && objectp(m->file)) { hp->feed (m->file->read()); if (m->file) { // Some wrappers may destruct themselves in read()... destruct(m->file); } } m = res && res[2]; } destruct (fake_id); return m; }
f47b662004-03-16Henrik Grubbström (Grubba) mapping(string:mixed) try_put_file(string path, string data, RequestID id) { TIMER_START(try_put_file); // id->misc->common is here for compatibility; it's better to use // id->root_id->misc. if ( !id->misc ) id->misc = ([]); if ( !id->misc->common ) id->misc->common = ([]); RequestID fake_id = id->clone_me(); fake_id->misc->common = id->misc->common; fake_id->misc->internal_get = 1; fake_id->conf = this_object(); fake_id->root_id->misc->_request_depth++; if(sub_req_limit && fake_id->root_id->misc->_request_depth > sub_req_limit) error("Subrequest limit reached. (Possibly an insertion loop.)"); if (fake_id->scan_for_query) // FIXME: If we're using e.g. ftp this doesn't exist. But the // right solution might be that clone_me() in an ftp id object // returns a vanilla (i.e. http) id instead when this function is // used. path = fake_id->scan_for_query(path); path = Roxen.fix_relative(path, id); fake_id->raw_url=path; fake_id->not_query=path; fake_id->method = "PUT"; fake_id->data = data; fake_id->misc->len = sizeof(data); fake_id->misc->internal_get = 1; mapping(string:mixed) res = low_get_file(fake_id, 1); TIMER_END(try_put_file); return res; }
7345b02001-09-13Martin Nilsson int(0..1) is_file(string virt_path, RequestID id, int(0..1)|void internal) //! Is @[virt_path] a file in our virtual filesystem? If @[internal] is //! set, internal files is "visible" as well.
14179b1997-01-29Per Hedbor {
7345b02001-09-13Martin Nilsson  if(internal) { int(0..1) was_internal = id->misc->internal_get; id->misc->internal_get = 1; int(0..1) res = !!stat_file(virt_path, id); if(!was_internal) m_delete(id->misc, "internal_get"); return res; } if(stat_file(virt_path, id) || has_suffix(virt_path, "/internal-roxen-unit")) return 1; string f = (virt_path/"/")[-1]; if( sscanf(f, "internal-roxen-%s", f) ) { if(internal_roxen_image(f, id) || has_prefix(f, "pixel-")) return 1; return 0; } if( sscanf(f, "internal-gopher-%s", f) && internal_gopher_image(f) ) return 1; return 0;
14179b1997-01-29Per Hedbor }
03aa492000-08-23Per Hedbor array registered_urls = ({}), failed_urls = ({ });
7a243b2000-08-19Per Hedbor array do_not_log_patterns = 0;
14179b1997-01-29Per Hedbor void start(int num) {
c109fc2001-07-21Martin Stjernholm  fix_my_url();
55c0522001-11-07Henrik Grubbström (Grubba) #if 0 report_debug(sprintf("configuration:start():\n" " registered_urls: ({ %{%O, %}})\n"
9c3c6c2001-11-09Henrik Grubbström (Grubba)  " failed_urls: ({ %{%O, %}})\n"
55c0522001-11-07Henrik Grubbström (Grubba)  " URLs: ({ %{%O, %}})\n", registered_urls, failed_urls, query("URLs"))); #endif /* 0 */
c5e0961999-10-04Per Hedbor  // Note: This is run as root if roxen is started as root
5d6c8d2000-09-01Per Hedbor  foreach( (registered_urls-query("URLs"))+failed_urls, string url ) { registered_urls -= ({ url });
9c3c6c2001-11-09Henrik Grubbström (Grubba)  roxen.unregister_url(url, this_object());
5d6c8d2000-09-01Per Hedbor  }
ecd9ab2000-08-23Per Hedbor 
03aa492000-08-23Per Hedbor  failed_urls = ({ });
ecd9ab2000-08-23Per Hedbor 
5d6c8d2000-09-01Per Hedbor  foreach( (query( "URLs" )-registered_urls), string url )
55c0522001-11-07Henrik Grubbström (Grubba)  {
ecd9ab2000-08-23Per Hedbor  if( roxen.register_url( url, this_object() ) ) registered_urls += ({ url });
03aa492000-08-23Per Hedbor  else failed_urls += ({ url });
55c0522001-11-07Henrik Grubbström (Grubba)  }
5f6dae2000-08-13Per Hedbor  if( !datacache ) datacache = DataCache( ); else datacache->init_from_variables();
7a243b2000-08-19Per Hedbor  parse_log_formats(); init_log_file(); do_not_log_patterns = query("NoLog"); if(!sizeof(do_not_log_patterns)) do_not_log_patterns = 0;
6f669a2001-08-14Honza Petrous 
b9c3872002-03-27Per Hedbor  if( query("throttle") ) { if( !throttler ) throttler=.throttler(); throttler->throttle(query("throttle_fill_rate"), query("throttle_bucket_depth"), query("throttle_min_grant"), query("throttle_max_grant")); } else if( throttler ) { // This is done to give old connections more bandwidth. throttler->throttle( 1000000000, 1000000000, // 800Mbit. 1024, 65536 ); // and new connections does not even have to care. throttler = 0; }
6f669a2001-08-14Honza Petrous #ifdef SNMP_AGENT if(query("snmp_process") && objectp(roxen->snmpagent)) roxen->snmpagent->add_virtserv(get_config_id()); #endif
14179b1997-01-29Per Hedbor }
e7e6031999-11-05Per Hedbor void save_me() { save_one( 0 ); }
14179b1997-01-29Per Hedbor void save(int|void all)
2688e22000-07-26Johan Sundström //! Save this configuration. If all is included, save all configuration //! global variables as well, otherwise only all module variables.
14179b1997-01-29Per Hedbor { if(all) {
3f628a1999-12-09Martin Stjernholm  store("spider#0", variables, 0, this_object());
14179b1997-01-29Per Hedbor  start(2); }
10c7e11999-12-28Martin Nilsson 
a2d0792002-04-15Marcus Wellhardh  store( "EnabledModules", enabled_modules, 1, this_object());
3f628a1999-12-09Martin Stjernholm  foreach(indices(modules), string modname)
14179b1997-01-29Per Hedbor  {
3f628a1999-12-09Martin Stjernholm  foreach(indices(modules[modname]->copies), int i)
14179b1997-01-29Per Hedbor  {
3f628a1999-12-09Martin Stjernholm  store(modname+"#"+i, modules[modname]->copies[i]->query(), 0, this_object());
49e3bc2001-03-12Anders Johansson  if (mixed err = catch(modules[modname]->copies[i]-> start(2, this_object()))) report_error("Error calling start in module.\n%s", describe_backtrace (err));
14179b1997-01-29Per Hedbor  } }
8cc31b1997-10-12Henrik Grubbström (Grubba)  invalidate_cache();
14179b1997-01-29Per Hedbor }
e351dd1999-11-29Per Hedbor int save_one( RoxenModule o )
2688e22000-07-26Johan Sundström //! Save all variables in a given module.
14179b1997-01-29Per Hedbor { mapping mod;
10c7e11999-12-28Martin Nilsson  if(!o)
14179b1997-01-29Per Hedbor  {
c5e0961999-10-04Per Hedbor  store("spider#0", variables, 0, this_object());
14179b1997-01-29Per Hedbor  start(2); return 1; }
2c13a81999-11-10Per Hedbor  string q = otomod[ o ]; if( !q ) error("Invalid module");
10c7e11999-12-28Martin Nilsson 
2c13a81999-11-10Per Hedbor  store(q, o->query(), 0, this_object()); invalidate_cache();
0d1e432000-11-02Per Hedbor  mixed error; if( error = catch( o->start(2, this_object()) ) ) { if( objectp(error ) ) error = (array)error; if( sizeof(error)>1 && arrayp( error[1] ) ) { int i; for( i = 0; i<sizeof( error[1] ); i++ ) if( error[1][i][2] == save_one ) break; error[1] = error[1][i+1..]; } if( o->report_error ) o->report_error( "Call to start failed.\n"+describe_backtrace( error ) ); else report_error( "Call to start failed.\n"+describe_backtrace( error )); }
2c13a81999-11-10Per Hedbor  invalidate_cache(); return 1;
14179b1997-01-29Per Hedbor }
2f79202000-03-27Per Hedbor RoxenModule reload_module( string modname )
5964251999-11-19Per Hedbor {
e351dd1999-11-29Per Hedbor  RoxenModule old_module = find_module( modname );
9a8a152000-09-25Per Hedbor  ModuleInfo mi = roxen.find_module( (modname/"#")[0] );
ffdab52001-08-24Per Hedbor 
f7c5742001-09-03Per Hedbor  roxen->bootstrap_info->set (({this_object(), modname }));
2f79202000-03-27Per Hedbor  if( !old_module ) return 0;
f569581999-11-23Per Hedbor 
b86de82000-11-13Per Hedbor  master()->clear_compilation_failures();
1f56521999-11-23Per Hedbor 
ffdab52001-08-24Per Hedbor  if( !old_module->not_a_module )
b86de82000-11-13Per Hedbor  { save_one( old_module ); master()->refresh_inherit( object_program( old_module ) ); master()->refresh( object_program( old_module ), 1 ); }
2f79202000-03-27Per Hedbor 
2141a12001-07-12Martin Stjernholm  array old_error_log = (array) old_module->error_log;
2f79202000-03-27Per Hedbor  RoxenModule nm;
2141a12001-07-12Martin Stjernholm 
ffdab52001-08-24Per Hedbor  // Load up a new instance.
7957982001-09-06Per Hedbor  nm = mi->instance( this_object() );
ffdab52001-08-24Per Hedbor  // If this is a faked module, let's call it a failure. if( nm->not_a_module ) {
9fa11d2001-08-24Martin Nilsson  old_module->report_error(LOC_C(385,"Reload failed")+"\n");
ffdab52001-08-24Per Hedbor  return old_module; }
bd86bd2001-09-06Per Hedbor  disable_module( modname, 1 ); destruct( old_module );
ffdab52001-08-24Per Hedbor  mi->update_with( nm,0 ); // This is sort of nessesary... enable_module( modname, nm, mi );
2141a12001-07-12Martin Stjernholm  foreach (old_error_log, [string msg, array(int) times]) nm->error_log[msg] += times; nm->report_notice(LOC_C(11, "Reloaded %s.")+"\n", mi->get_name());
2f79202000-03-27Per Hedbor  return nm;
5964251999-11-19Per Hedbor }
beba572000-03-20Martin Stjernholm #ifdef THREADS Thread.Mutex enable_modules_mutex = Thread.Mutex();
c6bf402001-09-10Martin Stjernholm #define MODULE_LOCK(TYPE) \ Thread.MutexKey enable_modules_lock = enable_modules_mutex->lock (TYPE)
beba572000-03-20Martin Stjernholm #else
c6bf402001-09-10Martin Stjernholm #define MODULE_LOCK(TYPE)
beba572000-03-20Martin Stjernholm #endif
9a1d472000-01-12Martin Stjernholm static int enable_module_batch_msgs;
2f79202000-03-27Per Hedbor RoxenModule enable_module( string modname, RoxenModule|void me,
bcf5662000-04-05Per Hedbor  ModuleInfo|void moduleinfo,
e6cd832002-04-09Marcus Wellhardh  int|void nostart, int|void nosave )
14179b1997-01-29Per Hedbor {
c6bf402001-09-10Martin Stjernholm  MODULE_LOCK (2);
c5e0961999-10-04Per Hedbor  int id;
e351dd1999-11-29Per Hedbor  ModuleCopies module;
c5e0961999-10-04Per Hedbor  int pr; mixed err; int module_type;
acff932001-08-14Per Hedbor  if( forcibly_added[modname] == 2 )
747a7c2001-08-13Per Hedbor  return search(otomod, modname);
4867e92000-09-05Per Hedbor  if( datacache ) datacache->flush();
8b16fe2000-09-05Per Hedbor 
e7e6031999-11-05Per Hedbor  if( sscanf(modname, "%s#%d", modname, id ) != 2 )
2f79202000-03-27Per Hedbor  while( modules[ modname ] && modules[ modname ][ id ] )
4f43eb1999-11-05Per Hedbor  id++;
c5e0961999-10-04Per Hedbor 
1e79252001-07-11Martin Stjernholm  roxen->bootstrap_info->set (({this_object(), modname + "#" + id}));
a42fe42001-07-05Martin Nilsson #ifdef MODULE_DEBUG
7f00081998-03-20Per Hedbor  int start_time = gethrtime();
a42fe42001-07-05Martin Nilsson #endif
25171c1999-11-06Per Hedbor 
2f79202000-03-27Per Hedbor  if( !moduleinfo )
ad683e1998-05-09Henrik Grubbström (Grubba)  {
2e8d0f2001-06-28Martin Stjernholm  moduleinfo = roxen->find_module( modname );
2f79202000-03-27Per Hedbor  if (!moduleinfo) { report_warning("Failed to load %s. The module probably " "doesn't exist in the module path.\n", modname);
8b700e2000-09-19Martin Stjernholm  got_no_delayed_load = -1;
3557f52001-06-30Martin Stjernholm  roxen->bootstrap_info->set (0);
2f79202000-03-27Per Hedbor  return 0; }
c5e0961999-10-04Per Hedbor  }
9a1d472000-01-12Martin Stjernholm  string descr = moduleinfo->get_name() + (id ? " copy " + (id + 1) : "");
835c6c2001-06-17Martin Nilsson  // sscanf(descr, "%*s: %s", descr);
9a1d472000-01-12Martin Stjernholm 
3bbda81997-06-11Henrik Grubbström (Grubba) #ifdef MODULE_DEBUG
9a1d472000-01-12Martin Stjernholm  if (enable_module_batch_msgs) report_debug(" %-43s... \b", descr );
c5e0961999-10-04Per Hedbor  else
9a1d472000-01-12Martin Stjernholm  report_debug("Enabling " + descr + "\n");
3bbda81997-06-11Henrik Grubbström (Grubba) #endif
c5e0961999-10-04Per Hedbor 
0b7d2b1999-12-22Per Hedbor  module = modules[ modname ];
c5e0961999-10-04Per Hedbor  if(!module)
7e446c1999-11-24Per Hedbor  modules[ modname ] = module = ModuleCopies();
c5e0961999-10-04Per Hedbor 
f569581999-11-23Per Hedbor  if( !me )
c5e0961999-10-04Per Hedbor  {
f569581999-11-23Per Hedbor  if(err = catch(me = moduleinfo->instance(this_object()))) {
c45b2a1999-12-09Martin Stjernholm #ifdef MODULE_DEBUG
9a1d472000-01-12Martin Stjernholm  if (enable_module_batch_msgs) report_debug("\bERROR\n");
67f60e2000-07-09Martin Nilsson  if (err != "") { #endif string bt=describe_backtrace(err);
434bac2000-07-14Andreas Lange  report_error("enable_module(): " +
49cd282000-08-11Andreas Lange  LOC_M(41, "Error while initiating module copy of %s%s"),
434bac2000-07-14Andreas Lange  moduleinfo->get_name(), (bt ? ":\n"+bt : "\n"));
67f60e2000-07-09Martin Nilsson #ifdef MODULE_DEBUG }
c45b2a1999-12-09Martin Stjernholm #endif
f63aca2000-09-08Martin Stjernholm  got_no_delayed_load = -1;
3557f52001-06-30Martin Stjernholm  roxen->bootstrap_info->set (0);
0b7d2b1999-12-22Per Hedbor  return module[id];
f569581999-11-23Per Hedbor  }
c5e0961999-10-04Per Hedbor  }
0b7d2b1999-12-22Per Hedbor  if(module[id] && module[id] != me)
c5e0961999-10-04Per Hedbor  {
0e1f262002-01-29Martin Stjernholm  if( module[id]->stop ) { if (err = catch( module[id]->stop() )) { string bt=describe_backtrace(err); report_error("disable_module(): " + LOC_M(44, "Error while disabling module %s%s"), descr, (bt ? ":\n"+bt : "\n")); } }
ad683e1998-05-09Henrik Grubbström (Grubba)  }
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  me->set_configuration( this_object() ); module_type = moduleinfo->type; if (module_type & (MODULE_LOCATION|MODULE_EXTENSION| MODULE_CONFIG|MODULE_FILE_EXTENSION|MODULE_LOGGER| MODULE_URL|MODULE_LAST|MODULE_PROVIDER|
b7b6532002-06-06Anders Johansson  MODULE_FILTER|MODULE_TAG|MODULE_FIRST| MODULE_USERDB))
ad683e1998-05-09Henrik Grubbström (Grubba)  {
c5e0961999-10-04Per Hedbor  if(module_type != MODULE_CONFIG)
3b17831998-11-22Per Hedbor  {
4770421999-11-22Henrik Grubbström (Grubba)  if (err = catch {
23414a2000-07-21Andreas Lange  me->defvar("_priority", 5, DLOCALE(12, "Priority"), TYPE_INT_LIST, DLOCALE(13, "The priority of the module. 9 is highest and 0 is lowest."
4770421999-11-22Henrik Grubbström (Grubba)  " Modules with the same priority can be assumed to be "
f498ed2000-07-11Martin Nilsson  "called in random order"),
4770421999-11-22Henrik Grubbström (Grubba)  ({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})); }) {
3557f52001-06-30Martin Stjernholm  roxen->bootstrap_info->set (0);
4770421999-11-22Henrik Grubbström (Grubba)  throw(err); }
3b17831998-11-22Per Hedbor  }
10c7e11999-12-28Martin Nilsson 
21306c2000-11-02Per Hedbor #ifdef MODULE_LEVEL_SECURITY
b7b6532002-06-06Anders Johansson  if( (module_type & ~(MODULE_LOGGER|MODULE_PROVIDER|MODULE_USERDB)) != 0 )
ad683e1998-05-09Henrik Grubbström (Grubba)  {
bc0fa02001-03-08Per Hedbor // me->defvar("_sec_group", "user", DLOCALE(14, "Security: Realm"), // TYPE_STRING, // DLOCALE(15, "The realm to use when requesting password from the " // "client. Usually used as an informative message to the " // "user."));
23414a2000-07-21Andreas Lange  me->defvar("_seclevels", "", DLOCALE(16, "Security: Patterns"), TYPE_TEXT_FIELD,
89d1d82001-05-16Martin Nilsson  DLOCALE(245,
62e2cb2001-03-08Per Hedbor  "The syntax is:\n" " \n<dl>" " <dt><b>userdb</b> <i>userdatabase module</i></dt>\n" " <dd> Select a non-default userdatabase module. The default is to " " search all modules. The userdatabase module config_userdb is always " " present, and contains the configuration users</dd>\n" "<dt><b>authmethod</b> <i>authentication module</i></dt>\n" "<dd>Select a non-default authentication method.</dd>" "<dt><b>realm</b> <i>realm name</i></dt>\n" "<dd>The realm is used when user authentication info is requested</dd>" "</dl>\n" " Below, CMD is one of 'allow' and 'deny'\n" " <dl>\n" " <dt>CMD <b>ip</b>=<i>ip/bits</i> [return]<br />\n" " CMD <b>ip</b>=<i>ip:mask</i> [return] <br />\n" " CMD <b>ip</b>=<i>pattern[,pattern,...]</i> [return] <br /></dt>\n" " <dd>Match the remote IP-address.</dd>\n" " \n" " <dt>CMD <b>user</b>=<i>name[,name,...]</i> [return]</dt>\n" " <dd>Requires a authenticated user. If the user name 'any' is used, any " "valid user will be OK. Otherwise, one of the listed users are required.</dd>" " <dt>CMD <b>group</b>=<i>name[,name,...]</i> [return]</dt>\n" "<dd>Requires a authenticated user with a group. If the group name " " 'any' is used, any valid group will be OK. Otherwise, one of the " "listed groups are required.</dd>\n" " \n" "<dt>CMD <b>dns</b>=<i>pattern[,pattern,...]</i> [return]</dt>\n" "<dd>Require one of the specified DNS domain-names</dd>" " \n" "<dt>CMD <b>time</b>=<i>HH:mm-HH:mm</i> [return]</dt>\n" "<dd>Only allow access to the module from the first time to the " " second each day. Both times should be specified in 24-hour " " HH:mm format.</dd>\n" "<dt>CMD <b>day</b>=<i>day[,day,...]</i> [return]</dt>\n" "<dd>Only allow access during certain days. Day is either a numerical "
d5a37b2004-02-20Martin Stjernholm  " value (Monday=1, Sunday=7) or a string (monday, tuesday etc)</dd>"
62e2cb2001-03-08Per Hedbor  "</dl><p>\n" " pattern is always a glob pattern (* = any characters, ? = any character).\n" "</p><p>\n" " return means that reaching this command results in immediate\n" " return, only useful for 'allow'.</p>\n" " \n" " <p>'deny' always implies a return, no futher testing is done if a\n" " 'deny' match.</p>\n"));
23414a2000-07-21Andreas Lange 
c5e0961999-10-04Per Hedbor  if(!(module_type & MODULE_PROXY))
14179b1997-01-29Per Hedbor  {
23414a2000-07-21Andreas Lange  me->defvar("_seclvl", 0, DLOCALE(18, "Security: Security level"), TYPE_INT,
55a8662000-11-20Per Hedbor  DLOCALE(305, "The modules security level is used to determine if a "
3bf3451998-10-01Peter Bortas  " 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>"
f498ed2000-07-11Martin Nilsson  " <li>A requests initial Trust level is infinitely high.</li>"
3bf3451998-10-01Peter Bortas  " <li> A request will only be handled by a module if its" " <i>trust level</i> is higher or equal to the"
f498ed2000-07-11Martin Nilsson  " <i>security level</i> of the module.</li>"
3bf3451998-10-01Peter Bortas  " <li> Each time the request is handled by a module the" " <i>trust level</i> of the module will be set to the" " lower of its <i>trust level</i> and the modules"
90ecbb2000-11-15Per Hedbor  " <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>"
f498ed2000-07-11Martin Nilsson  " </ul></p>"
3bf3451998-10-01Peter Bortas  "\n<p><h2>Example</h2>" " Modules:<ul>"
f498ed2000-07-11Martin Nilsson  " <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>"
3bf3451998-10-01Peter Bortas  "\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"
f498ed2000-07-11Martin Nilsson  " level.</p>"
3bf3451998-10-01Peter Bortas  "\n<p>On the other hand, a request handled by the the" " \"Filsystem module\" could later be handled by the"
f498ed2000-07-11Martin Nilsson  " \"CGI module\".</p>"));
ad683e1998-05-09Henrik Grubbström (Grubba)  } else { me->definvisvar("_seclvl", -10, TYPE_INT); /* A very low one */
14179b1997-01-29Per Hedbor  }
3bbda81997-06-11Henrik Grubbström (Grubba)  }
21306c2000-11-02Per Hedbor #endif
ad683e1998-05-09Henrik Grubbström (Grubba)  } else { me->defvar("_priority", 0, "", TYPE_INT, "", 0, 1); }
14179b1997-01-29Per Hedbor 
a0fbcc2000-04-05Martin Stjernholm  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);
33e6351998-02-28Martin Stjernholm 
0b7d2b1999-12-22Per Hedbor  module[ id ] = me;
37c1b31999-10-12Per Hedbor  otomod[ me ] = modname+"#"+id;
10c7e11999-12-28Martin Nilsson 
bcf5662000-04-05Per Hedbor  if(!nostart) call_start_callbacks( me, moduleinfo, module ); #ifdef MODULE_DEBUG
be87a72002-04-17Marcus Wellhardh  if (enable_module_batch_msgs) { if(moduleinfo->config_locked[this_object()]) report_debug("\bLocked %6.1fms\n", (gethrtime()-start_time)/1000.0); else report_debug("\bOK %6.1fms\n", (gethrtime()-start_time)/1000.0); } #else if(moduleinfo->config_locked[this_object()]) report_error(" Error: \"%s\" not loaded (license restriction).\n", moduleinfo->get_name());
bcf5662000-04-05Per Hedbor #endif
fd24e22000-08-28Per Hedbor  if( !enabled_modules[modname+"#"+id] ) { enabled_modules[modname+"#"+id] = 1;
e6cd832002-04-09Marcus Wellhardh  if(!nosave) store( "EnabledModules", enabled_modules, 1, this_object());
fd24e22000-08-28Per Hedbor  }
6f595f2000-08-20Per Hedbor 
e6cd832002-04-09Marcus Wellhardh  if (!has_stored_vars && !nosave)
bcf5662000-04-05Per Hedbor  store (modname + "#" + id, me->query(), 0, this_object());
f63aca2000-09-08Martin Stjernholm  if( me->no_delayed_load && got_no_delayed_load >= 0 ) got_no_delayed_load = 1;
a8ba692000-08-29Marcus Wellhardh 
3557f52001-06-30Martin Stjernholm  roxen->bootstrap_info->set (0);
bcf5662000-04-05Per Hedbor  return me; } void call_start_callbacks( RoxenModule me, ModuleInfo moduleinfo, ModuleCopies module ) {
a8ba692000-08-29Marcus Wellhardh  call_low_start_callbacks( me, moduleinfo, module );
79538a2002-12-10Martin Stjernholm  call_high_start_callbacks (me, moduleinfo);
a8ba692000-08-29Marcus Wellhardh } void call_low_start_callbacks( RoxenModule me, ModuleInfo moduleinfo, ModuleCopies module ) {
40f0642000-09-13Per Hedbor  if(!me) return; if(!moduleinfo) return; if(!module) return;
a8ba692000-08-29Marcus Wellhardh  int module_type = moduleinfo->type, pr; mixed err;
10c7e11999-12-28Martin Nilsson  if (err = catch(pr = me->query("_priority")))
c5e0961999-10-04Per Hedbor  {
c45b2a1999-12-09Martin Stjernholm #ifdef MODULE_DEBUG
9a1d472000-01-12Martin Stjernholm  if (enable_module_batch_msgs) report_debug("\bERROR\n");
c45b2a1999-12-09Martin Stjernholm #endif
67f60e2000-07-09Martin Nilsson  string bt=describe_backtrace(err);
49cd282000-08-11Andreas Lange  report_error(LOC_M(41, "Error while initiating module copy of %s%s"),
67f60e2000-07-09Martin Nilsson  moduleinfo->get_name(), (bt ? ":\n"+bt : "\n"));
ad683e1998-05-09Henrik Grubbström (Grubba)  pr = 3; } api_module_cache |= me->api_functions();
10c7e11999-12-28Martin Nilsson  if(module_type & MODULE_EXTENSION)
c5e0961999-10-04Per Hedbor  {
434bac2000-07-14Andreas Lange  report_error("%s is an MODULE_EXTENSION, that type is no " "longer available.\nPlease notify the modules writer.\n" "Suitable replacement types include MODULE_FIRST and " " MODULE_LAST.\n", moduleinfo->get_name());
c5e0961999-10-04Per Hedbor  }
ad683e1998-05-09Henrik Grubbström (Grubba) 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_FILE_EXTENSION)
ad683e1998-05-09Henrik Grubbström (Grubba)  if (err = catch { array arr = me->query_file_extensions();
10c7e11999-12-28Martin Nilsson  if (arrayp(arr))
c5e0961999-10-04Per Hedbor  {
ad683e1998-05-09Henrik Grubbström (Grubba)  string foo; foreach( me->query_file_extensions(), foo )
0ba0382001-08-28Henrik Grubbström (Grubba)  if(pri[pr]->file_extension_modules[foo = lower_case(foo)] ) pri[pr]->file_extension_modules[foo] += ({me});
ad683e1998-05-09Henrik Grubbström (Grubba)  else
0ba0382001-08-28Henrik Grubbström (Grubba)  pri[pr]->file_extension_modules[foo] = ({me});
ad683e1998-05-09Henrik Grubbström (Grubba)  }
c45b2a1999-12-09Martin Stjernholm  }) { #ifdef MODULE_DEBUG
9a1d472000-01-12Martin Stjernholm  if (enable_module_batch_msgs) report_debug("\bERROR\n");
c45b2a1999-12-09Martin Stjernholm #endif
f63aca2000-09-08Martin Stjernholm  string bt=describe_backtrace(err); report_error(LOC_M(41, "Error while initiating module copy of %s%s"), moduleinfo->get_name(), (bt ? ":\n"+bt : "\n")); got_no_delayed_load = -1;
c45b2a1999-12-09Martin Stjernholm  }
14179b1997-01-29Per Hedbor 
10c7e11999-12-28Martin Nilsson  if(module_type & MODULE_PROVIDER) if (err = catch
c5e0961999-10-04Per Hedbor  {
747a7c2001-08-13Per Hedbor  mixed provs = me->query_provides ? me->query_provides() : ({});
ad683e1998-05-09Henrik Grubbström (Grubba)  if(stringp(provs)) provs = (< provs >); if(arrayp(provs)) provs = mkmultiset(provs); if (multisetp(provs)) { pri[pr]->provider_modules [ me ] = provs;
3bbda81997-06-11Henrik Grubbström (Grubba)  }
c45b2a1999-12-09Martin Stjernholm  }) { #ifdef MODULE_DEBUG
9a1d472000-01-12Martin Stjernholm  if (enable_module_batch_msgs) report_debug("\bERROR\n");
c45b2a1999-12-09Martin Stjernholm #endif
f63aca2000-09-08Martin Stjernholm  string bt=describe_backtrace(err); report_error(LOC_M(41, "Error while initiating module copy of %s%s"), moduleinfo->get_name(), (bt ? ":\n"+bt : "\n")); got_no_delayed_load = -1;
c45b2a1999-12-09Martin Stjernholm  }
10c7e11999-12-28Martin Nilsson 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_TYPES)
ad683e1998-05-09Henrik Grubbström (Grubba)  { types_module = me; types_fun = me->type_from_extension; }
10c7e11999-12-28Martin Nilsson 
f590762000-09-10Martin Nilsson  if(module_type & MODULE_TAG)
c5e0961999-10-04Per Hedbor  add_parse_module( me );
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_DIRECTORIES)
aaf3912000-09-19Jonas Wallden  if (me->parse_directory) dir_module = me;
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_LOCATION)
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->location_modules += ({ me });
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_LOGGER)
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->logger_modules += ({ me });
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_URL)
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->url_modules += ({ me });
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_LAST)
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->last_modules += ({ me });
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if(module_type & MODULE_FILTER)
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->filter_modules += ({ me });
14179b1997-01-29Per Hedbor 
10c7e11999-12-28Martin Nilsson  if(module_type & MODULE_FIRST)
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->first_modules += ({ me });
14179b1997-01-29Per Hedbor 
ad683e1998-05-09Henrik Grubbström (Grubba)  invalidate_cache();
14179b1997-01-29Per Hedbor }
79538a2002-12-10Martin Stjernholm void call_high_start_callbacks (RoxenModule me, ModuleInfo moduleinfo) { // This is icky, but I don't know if it's safe to remove. /mast if(!me) return; if(!moduleinfo) return; mixed err; if((me->start) && (err = catch( me->start(0, this_object()) ) ) ) { #ifdef MODULE_DEBUG if (enable_module_batch_msgs) report_debug("\bERROR\n"); #endif string bt=describe_backtrace(err); report_error(LOC_M(41, "Error while initiating module copy of %s%s"), moduleinfo->get_name(), (bt ? ":\n"+bt : "\n")); got_no_delayed_load = -1; } if( inited && me->ready_to_receive_requests ) if( mixed q = catch( me->ready_to_receive_requests( this_object() ) ) ) { #ifdef MODULE_DEBUG if (enable_module_batch_msgs) report_debug("\bERROR\n"); #endif report_error( "While calling ready_to_receive_requests:\n"+ describe_backtrace( q ) ); got_no_delayed_load = -1; } }
a6ef1f2000-03-28Johan Sundström // Called from the administration interface.
199d031999-09-05Francesco Chemolli string check_variable(string name, mixed value)
14179b1997-01-29Per Hedbor { switch(name) {
cffbaa2000-04-11Per Hedbor // case "MyWorldLocation": // if(strlen(value)<7 || value[-1] != '/' || // !(sscanf(value,"%*s://%*s/")==2)) // return LOCALE->url_format(); // return 0;
c109fc2001-07-21Martin Stjernholm  case "MyWorldLocation": case "URLs": fix_my_url(); return 0;
b9c3872002-03-27Per Hedbor // case "throttle": // // There was code here to sett the throttling. That's not a // // good idea. Moved to start. The code now also avoids // // creating new throttle objects each time a value is changed. // case "throttle_fill_rate": // case "throttle_bucket_depth": // case "throttle_min_grant": // case "throttle_max_grant": // return 0;
e427912001-06-30Honza Petrous #ifdef SNMP_AGENT case "snmp_process": if (objectp(roxen->snmpagent)) { int cid = get_config_id(); value ? roxen->snmpagent->add_virtserv(cid) : roxen->snmpagent->del_virtserv(cid); } return 0; #endif
14179b1997-01-29Per Hedbor  } }
2f4ac12000-11-02Per Hedbor void module_changed( ModuleInfo moduleinfo, RoxenModule me )
14179b1997-01-29Per Hedbor {
2f4ac12000-11-02Per Hedbor  clean_up_for_module( moduleinfo, me ); call_low_start_callbacks( me, moduleinfo, modules[ moduleinfo->sname ] ); }
14179b1997-01-29Per Hedbor 
2f4ac12000-11-02Per Hedbor void clean_up_for_module( ModuleInfo moduleinfo, RoxenModule me ) { int pr;
c5e0961999-10-04Per Hedbor  if(moduleinfo->type & MODULE_FILE_EXTENSION)
14179b1997-01-29Per Hedbor  { string foo;
d54d061999-06-10Martin Stjernholm  for(pr=0; pr<10; pr++) foreach( indices (pri[pr]->file_extension_modules), foo ) pri[pr]->file_extension_modules[foo]-=({me});
14179b1997-01-29Per Hedbor  }
c5e0961999-10-04Per Hedbor  if(moduleinfo->type & MODULE_PROVIDER) {
ae32d01998-03-23David Hedbor  for(pr=0; pr<10; pr++) m_delete(pri[pr]->provider_modules, me); }
10c7e11999-12-28Martin Nilsson 
c5e0961999-10-04Per Hedbor  if(moduleinfo->type & MODULE_TYPES)
14179b1997-01-29Per Hedbor  { types_module = 0; types_fun = 0; }
f590762000-09-10Martin Nilsson  if(moduleinfo->type & MODULE_TAG)
b796b51998-11-18Per Hedbor  remove_parse_module( me );
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_DIRECTORIES )
14179b1997-01-29Per Hedbor  dir_module = 0;
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_LOCATION )
14179b1997-01-29Per Hedbor  for(pr=0; pr<10; pr++) pri[pr]->location_modules -= ({ me });
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_URL )
14179b1997-01-29Per Hedbor  for(pr=0; pr<10; pr++) pri[pr]->url_modules -= ({ me });
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_LAST )
14179b1997-01-29Per Hedbor  for(pr=0; pr<10; pr++) pri[pr]->last_modules -= ({ me });
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_FILTER )
14179b1997-01-29Per Hedbor  for(pr=0; pr<10; pr++) pri[pr]->filter_modules -= ({ me });
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_FIRST ) {
14179b1997-01-29Per Hedbor  for(pr=0; pr<10; pr++) pri[pr]->first_modules -= ({ me });
f128901997-08-15Henrik Grubbström (Grubba)  }
14179b1997-01-29Per Hedbor 
c5e0961999-10-04Per Hedbor  if( moduleinfo->type & MODULE_LOGGER )
14179b1997-01-29Per Hedbor  for(pr=0; pr<10; pr++) pri[pr]->logger_modules -= ({ me });
2f4ac12000-11-02Per Hedbor } int disable_module( string modname, int|void nodest ) {
c6bf402001-09-10Martin Stjernholm  MODULE_LOCK (2);
2f4ac12000-11-02Per Hedbor  RoxenModule me; int id, pr; sscanf(modname, "%s#%d", modname, id ); if( datacache ) datacache->flush(); ModuleInfo moduleinfo = roxen.find_module( modname ); mapping module = modules[ modname ]; string descr = moduleinfo->get_name() + (id ? " copy " + (id + 1) : ""); if(!module) { report_error("disable_module(): " + LOC_M(42, "Failed to disable module:\n" "No module by that name: \"%s\".\n"), modname); return 0; } me = module[id]; m_delete(module->copies, id); if(!sizeof(module->copies)) m_delete( modules, modname ); invalidate_cache(); if(!me) { report_error("disable_module(): " + LOC_M(43, "Failed to disable module \"%s\".\n"), descr); return 0; } if(me->stop) if (mixed err = catch (me->stop())) { string bt=describe_backtrace(err); report_error("disable_module(): " + LOC_M(44, "Error while disabling module %s%s"), descr, (bt ? ":\n"+bt : "\n")); } #ifdef MODULE_DEBUG report_debug("Disabling "+descr+"\n"); #endif
14179b1997-01-29Per Hedbor 
2f4ac12000-11-02Per Hedbor  clean_up_for_module( moduleinfo, me );
14179b1997-01-29Per Hedbor 
5fbaec2001-04-11Per Hedbor  if( !nodest ) {
a42fe42001-07-05Martin Nilsson  m_delete( enabled_modules, modname + "#" + id );
acff932001-08-14Per Hedbor  m_delete( forcibly_added, modname + "#" + id );
5fbaec2001-04-11Per Hedbor  store( "EnabledModules",enabled_modules, 1, this_object());
2f79202000-03-27Per Hedbor  destruct(me);
5fbaec2001-04-11Per Hedbor  }
14179b1997-01-29Per Hedbor  return 1; }
9a8a152000-09-25Per Hedbor RoxenModule find_module(string name)
9fd8092000-08-08Johan Sundström //! Return the module corresponding to the name (eg "rxmlparse", //! "rxmlparse#0" or "filesystem#1") or zero, if there was no such
d5c8642001-08-23Martin Stjernholm //! module. The string is on the same format as the one returned by //! @[RoxenModule.module_local_id].
14179b1997-01-29Per Hedbor { int id; sscanf(name, "%s#%d", name, id); if(modules[name])
c5e0961999-10-04Per Hedbor  return modules[name]->copies[id];
14179b1997-01-29Per Hedbor  return 0; }
acff932001-08-14Per Hedbor mapping forcibly_added = ([]);
f5a2741999-10-18Per Hedbor int add_modules( array(string) mods, int|void now )
14179b1997-01-29Per Hedbor {
ba18d71999-11-27Per Hedbor #ifdef MODULE_DEBUG
c5e0961999-10-04Per Hedbor  int wr;
ba18d71999-11-27Per Hedbor #endif
c5e0961999-10-04Per Hedbor  foreach (mods, string mod)
8f061b1999-11-19Per Hedbor  { sscanf( mod, "%s#", mod );
10c7e11999-12-28Martin Nilsson  if( ((now && !modules[ mod ]) ||
0ce25d1999-11-15Per Hedbor  !enabled_modules[ mod+"#0" ] ) && !forcibly_added[ mod+"#0" ])
14179b1997-01-29Per Hedbor  {
ba18d71999-11-27Per Hedbor #ifdef MODULE_DEBUG
c5e0961999-10-04Per Hedbor  if( !wr++ )
9a1d472000-01-12Martin Stjernholm  if (enable_module_batch_msgs) report_debug("\b[ adding req module" + (sizeof (mods) > 1 ? "s" : "") + "\n"); else report_debug("Adding required module" + (sizeof (mods) > 1 ? "s" : "") + "\n");
14179b1997-01-29Per Hedbor #endif
747a7c2001-08-13Per Hedbor  forcibly_added[ mod+"#0" ] = 1;
acff932001-08-14Per Hedbor  enable_module( mod+"#0" ); forcibly_added[ mod+"#0" ] = 2;
14179b1997-01-29Per Hedbor  }
8f061b1999-11-19Per Hedbor  }
ba18d71999-11-27Per Hedbor #ifdef MODULE_DEBUG
9a1d472000-01-12Martin Stjernholm  if( wr && enable_module_batch_msgs )
ed8d261999-12-30Martin Stjernholm  report_debug("] \b");
c79b261998-02-05Johan Schön #endif
14179b1997-01-29Per Hedbor }
850c282001-01-10Per Hedbor #if ROXEN_COMPAT < 2.2
279a0c1997-11-26Henrik Grubbström (Grubba) // BEGIN SQL
14179b1997-01-29Per Hedbor 
279a0c1997-11-26Henrik Grubbström (Grubba) mapping(string:string) sql_urls = ([]);
3f059e2001-06-24Per Hedbor constant sql_cache_get = DBManager.sql_cache_get;
ed93131998-07-09Johan Schön 
850c282001-01-10Per Hedbor Sql.Sql sql_connect(string db)
279a0c1997-11-26Henrik Grubbström (Grubba) {
c5e0961999-10-04Per Hedbor  if (sql_urls[db]) return sql_cache_get(sql_urls[db]); else return sql_cache_get(db);
279a0c1997-11-26Henrik Grubbström (Grubba) } // END SQL
850c282001-01-10Per Hedbor #endif
14179b1997-01-29Per Hedbor 
c109fc2001-07-21Martin Stjernholm static string my_url; void fix_my_url()
14179b1997-01-29Per Hedbor {
c109fc2001-07-21Martin Stjernholm  my_url = query ("MyWorldLocation");
f418572001-07-21Martin Stjernholm  if (!sizeof (my_url) && !(my_url = Roxen.get_world (query ("URLs"))))
3ec7cf2001-07-21Martin Stjernholm  // Probably no port configured. The empty string is used as a // flag; there shouldn't be any bad fallback here. my_url = ""; else if (!has_suffix (my_url, "/")) my_url += "/";
14179b1997-01-29Per Hedbor }
6b67fe2001-08-24Martin Nilsson //! Returns some URL for accessing the configuration. (Should be //! used instead of querying MyWorldLocation directly.)
c109fc2001-07-21Martin Stjernholm string get_url() {return my_url;}
5ffa542000-02-16Per Hedbor array after_init_hooks = ({}); mixed add_init_hook( mixed what ) { if( inited ) call_out( what, 0, this_object() ); else after_init_hooks |= ({ what }); }
d53f0b2000-09-09Martin Stjernholm static int got_no_delayed_load = 0;
c6bf402001-09-10Martin Stjernholm // 0 -> enable delayed loading, 1 -> disable delayed loading,
f63aca2000-09-08Martin Stjernholm // -1 -> don't change.
d53f0b2000-09-09Martin Stjernholm void fix_no_delayed_load_flag()
14179b1997-01-29Per Hedbor {
d53f0b2000-09-09Martin Stjernholm  if( got_no_delayed_load >= 0 && query ("no_delayed_load") != got_no_delayed_load ) {
f63aca2000-09-08Martin Stjernholm  set( "no_delayed_load", got_no_delayed_load );
c45e3f2000-02-16Per Hedbor  save_one( 0 );
f63aca2000-09-08Martin Stjernholm  }
5ffa542000-02-16Per Hedbor }
d53f0b2000-09-09Martin Stjernholm void enable_all_modules() {
c6bf402001-09-10Martin Stjernholm  MODULE_LOCK (0);
d53f0b2000-09-09Martin Stjernholm  low_init( ); fix_no_delayed_load_flag(); } void low_init(void|int modules_already_enabled)
5ffa542000-02-16Per Hedbor { if( inited ) return; // already done
8516a71999-12-22Per Hedbor 
24c06c2000-02-16Per Hedbor  int start_time = gethrtime();
d53f0b2000-09-09Martin Stjernholm  if (!modules_already_enabled) report_debug("\nEnabling all modules for "+query_name()+"... \n");
24c06c2000-02-16Per Hedbor 
f7c5742001-09-03Per Hedbor  if (!modules_already_enabled) {
d53f0b2000-09-09Martin Stjernholm  enabled_modules = retrieve("EnabledModules", this_object());
747a7c2001-08-13Per Hedbor // roxenloader.LowErrorContainer ec = roxenloader.LowErrorContainer(); // roxenloader.push_compile_error_handler( ec );
d53f0b2000-09-09Martin Stjernholm  array modules_to_process = indices( enabled_modules ); string tmp_string;
0e1f262002-01-29Martin Stjernholm  mixed err;
acff932001-08-14Per Hedbor  forcibly_added = ([]);
d53f0b2000-09-09Martin Stjernholm  enable_module_batch_msgs = 1; foreach( modules_to_process, tmp_string ) { if( !forcibly_added[ tmp_string ] )
747a7c2001-08-13Per Hedbor  if(err = catch( enable_module( tmp_string ))) { report_error(LOC_M(45, "Failed to enable the module %s. Skipping.") +"\n%s\n", tmp_string, describe_backtrace(err));
d53f0b2000-09-09Martin Stjernholm  got_no_delayed_load = -1; } } enable_module_batch_msgs = 0; roxenloader.pop_compile_error_handler();
acff932001-08-14Per Hedbor  forcibly_added = ([]);
f5a2741999-10-18Per Hedbor  }
17d6d12000-03-30Per Hedbor 
3e3bab2001-01-19Per Hedbor  foreach( ({this_object()})+indices( otomod ), RoxenModule mod )
5ffa542000-02-16Per Hedbor  if( mod->ready_to_receive_requests )
f63aca2000-09-08Martin Stjernholm  if( mixed q = catch( mod->ready_to_receive_requests( this_object() ) ) ) {
c2fdff2000-03-21Martin Stjernholm  report_error( "While calling ready_to_receive_requests in "+
5ffa542000-02-16Per Hedbor  otomod[mod]+":\n"+ describe_backtrace( q ) );
f63aca2000-09-08Martin Stjernholm  got_no_delayed_load = -1; }
5ffa542000-02-16Per Hedbor  foreach( after_init_hooks, function q )
f63aca2000-09-08Martin Stjernholm  if( mixed w = catch( q(this_object()) ) ) {
c2fdff2000-03-21Martin Stjernholm  report_error( "While calling after_init_hook %O:\n%s",
5ffa542000-02-16Per Hedbor  q, describe_backtrace( w ) );
f63aca2000-09-08Martin Stjernholm  got_no_delayed_load = -1; }
5ffa542000-02-16Per Hedbor  after_init_hooks = ({}); inited = 1;
d53f0b2000-09-09Martin Stjernholm  if (!modules_already_enabled) report_notice(LOC_S(4, "All modules for %s enabled in %3.1f seconds") + "\n\n", query_name(), (gethrtime()-start_time)/1000000.0);
14cf2b2001-07-18Honza Petrous  #ifdef SNMP_AGENT
79b7c32001-09-13Honza Petrous  // Start trap after real virt.serv. loading if(query("snmp_process") && objectp(roxen->snmpagent)) roxen->snmpagent->vs_start_trap(get_config_id());
14cf2b2001-07-18Honza Petrous #endif
0f28da1997-08-13Per Hedbor }
5f6dae2000-08-13Per Hedbor DataCache datacache;
3557f52001-06-30Martin Stjernholm static void create()
0f28da1997-08-13Per Hedbor {
3557f52001-06-30Martin Stjernholm  if (!name) error ("Configuration name not set through bootstrap_info.\n");
8514832000-11-27Per Hedbor // int st = gethrtime();
3557f52001-06-30Martin Stjernholm  roxen.add_permission( "Site:"+name, LOC_C(306,"Site")+": "+name );
62e1bb2000-11-08Per Hedbor 
b0a9ea2001-04-18Martin Stjernholm  // for now only these two. In the future there might be more variables.
224f182002-05-13Jonas Wallden  defvar( "data_cache_size", 16384, DLOCALE(274, "Cache:Cache size"),
e4e6d32000-11-02Per Hedbor  TYPE_INT| VAR_PUBLIC,
99a7452000-08-22Andreas Lange  DLOCALE(275, "The size of the data cache used to speed up requests "
5f6dae2000-08-13Per Hedbor  "for commonly requested files, in KBytes"));
224f182002-05-13Jonas Wallden  defvar( "data_cache_file_max_size", 100, DLOCALE(276, "Cache:Max file size"),
e4e6d32000-11-02Per Hedbor  TYPE_INT | VAR_PUBLIC,
99a7452000-08-22Andreas Lange  DLOCALE(277, "The maximum size of a file that is to be considered for "
0c62792003-01-21Martin Stjernholm  "the cache, in KBytes."));
5f6dae2000-08-13Per Hedbor 
23414a2000-07-21Andreas Lange  defvar("default_server", 0, DLOCALE(20, "Default site"),
e4e6d32000-11-02Per Hedbor  TYPE_FLAG| VAR_PUBLIC,
23414a2000-07-21Andreas Lange  DLOCALE(21, "If true, this site will be selected in preference of "
40e24c2000-05-27Per Hedbor  "other sites when virtual hosting is used and no host " "header is supplied, or the supplied host header does not "
f498ed2000-07-11Martin Nilsson  "match the address of any of the other servers.") );
40e24c2000-05-27Per Hedbor 
1dd64a2000-09-19Mattias Wingstedt  defvar("comment", "", DLOCALE(22, "Site comment"),
9b9f701997-08-12Per Hedbor  TYPE_TEXT_FIELD|VAR_MORE,
23414a2000-07-21Andreas Lange  DLOCALE(23, "This text will be visible in the administration "
434bac2000-07-14Andreas Lange  "interface, it can be quite useful to use as a memory helper."));
b796b51998-11-18Per Hedbor 
1dd64a2000-09-19Mattias Wingstedt  defvar("name", "", DLOCALE(24, "Site name"),
b98c022001-07-31Per Hedbor  TYPE_STRING|VAR_MORE| VAR_PUBLIC|VAR_NO_DEFAULT,
8148ed2000-09-13Andreas Lange  DLOCALE(25, "This is the name that will be used in the administration "
14179b1997-01-29Per Hedbor  "interface. If this is left empty, the actual name of the "
1dd64a2000-09-19Mattias Wingstedt  "site will be used."));
10c7e11999-12-28Martin Nilsson 
b0a9ea2001-04-18Martin Stjernholm  defvar("compat_level", Variable.StringChoice (
b98c022001-07-31Per Hedbor  "", roxen.compat_levels, VAR_NO_DEFAULT,
89d1d82001-05-16Martin Nilsson  DLOCALE(246, "Compatibility level"),
295f8d2002-08-13Martin Stjernholm  DLOCALE(386, #"\ <p>The compatibility level is used by different modules to select the right behavior to remain compatible with earlier Roxen versions. When 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 issues with 2.4, notably the optimization of cache static tags in the &lt;cache&gt; tag.</td></tr>
e3cb7d2002-09-02Martin Stjernholm <tr valign='top'><td>3.3&nbsp;&nbsp;</td>
b4f65c2003-01-13Martin Stjernholm  <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>
ade3d22004-05-28Jonas Wallden <tr valign='top'><td>4.0&nbsp;&nbsp;</td> <td>Corresponds to Roxen 4.0.</td></tr>
295f8d2002-08-13Martin Stjernholm </table></p>")));
b0a9ea2001-04-18Martin Stjernholm  set ("compat_level", roxen.__roxen_version__);
7848ae2001-06-15Martin Stjernholm  // 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 // the setting.
b0a9ea2001-04-18Martin Stjernholm 
5467e92001-10-05Per Hedbor  defvar("Log", 1, DLOCALE(28, "Logging: Enabled"), TYPE_FLAG, DLOCALE(29, "Log requests"));
10c7e11999-12-28Martin Nilsson  defvar("LogFormat",
f498ed2000-07-11Martin Nilsson  "404: $host $referer - [$cern_date] \"$method $resource $protocol\" 404 -\n" "500: $host $referer ERROR [$cern_date] \"$method $resource $protocol\" 500 -\n" "*: $host - - [$cern_date] \"$method $resource $protocol\" $response $length",
23414a2000-07-21Andreas Lange  DLOCALE(26, "Logging: Format"),
9b9f701997-08-12Per Hedbor  TYPE_TEXT_FIELD|VAR_MORE,
46d4cb2001-08-22Martin Stjernholm  DLOCALE(27, #"What format to use for logging. The syntax is: <pre>response-code or *: Log format for that response code Log format is normal characters, or one or more of the variables below:
0e20f32002-05-29Anders Johansson \\n \\t \\r -- As in C, newline, tab and linefeed $char(int) -- Insert the (1 byte) character specified by the integer. $wchar(int) -- Insert the (2 byte) word specified by the integer. $int(int) -- Insert the (4 byte) word specified by the integer. $^ -- Supress newline at the end of the logentry $host -- The remote host name, or ip number. $vhost -- The Host request-header sent by the client, or - if none $ip_number -- The remote ip number. $bin-ip_number -- The remote host id as a binary integer number. $cern_date -- Cern Common Log file format date. $bin-date -- Time, but as an 32 bit integer in network byteorder $method -- Request method $resource -- Resource identifier $full_resource -- Full requested resource, including any query fields $protocol -- The protocol used (normally HTTP/1.0) $response -- The response code sent $bin-response -- The response code sent as a binary short number $length -- The length of the data section of the reply $bin-length -- Same, but as an 32 bit integer in network byteorder $request-time -- The time the request took (seconds) $referer -- The header 'referer' from the request, or '-'. $user_agent -- The header 'User-Agent' from the request, or '-'.
f9ce962002-05-29Anders Johansson $user_agent_raw -- Same, but spaces in the name are not encoded to %20.
0e20f32002-05-29Anders Johansson $user -- the name of the auth user used, if any $user_id -- A unique user ID, if cookies are supported, by the client, otherwise '0' $cache-status -- A comma separated list of words (containing no whitespace) that describes which cache(s) the page was delivered from: protcache -- The low-level cache in the HTTP protocol module. xsltcache -- The XSLT cache. pcoderam -- RXML parse tree RAM cache. pcodedisk -- RXML parse tree persistent cache. cachetag -- No RXML &lt;cache&gt; tag misses. nocache -- No hit in any known cache.
46d4cb2001-08-22Martin Stjernholm </pre>"), 0, lambda(){ return !query("Log");});
b796b51998-11-18Per Hedbor 
f498ed2000-07-11Martin Nilsson  // FIXME: Mention it is relative to getcwd(). Can not be localized in pike 7.0. defvar("LogFile", "$LOGDIR/"+Roxen.short_name(name)+"/Log",
23414a2000-07-21Andreas Lange  DLOCALE(30, "Logging: Log file"), TYPE_FILE, DLOCALE(31, "The log file. "
f7d9811997-09-12Per Hedbor  ""
f498ed2000-07-11Martin Nilsson  "A file name. Some substitutions will be done:"
f7d9811997-09-12Per Hedbor  "<pre>"
b796b51998-11-18Per Hedbor  "%y Year (e.g. '1997')\n" "%m Month (e.g. '08')\n" "%d Date (e.g. '10' for the tenth)\n"
3bb38c2000-01-20Martin Bähr  "%h Hour (e.g. '00')\n" "%H Hostname\n"
f498ed2000-07-11Martin Nilsson  "</pre>")
c5e0961999-10-04Per Hedbor  ,0, lambda(){ return !query("Log");});
10c7e11999-12-28Martin Nilsson  defvar("NoLog", ({ }),
23414a2000-07-21Andreas Lange  DLOCALE(32, "Logging: No Logging for"), TYPE_STRING_LIST|VAR_MORE, DLOCALE(33, "Don't log requests from hosts with an IP number which "
434bac2000-07-14Andreas Lange  "matches any of the patterns in this list. This also affects " "the access counter log."), 0, lambda(){ return !query("Log");});
a8f1b32000-01-31Per Hedbor 
e4e6d32000-11-02Per Hedbor  defvar("Domain", roxen.get_domain(), DLOCALE(34, "Domain"),
b98c022001-07-31Per Hedbor  TYPE_STRING|VAR_PUBLIC|VAR_NO_DEFAULT,
1dd64a2000-09-19Mattias Wingstedt  DLOCALE(35, "The domain name of the server. The domain name is used "
434bac2000-07-14Andreas Lange  "to generate default URLs, and to generate email addresses."));
14179b1997-01-29Per Hedbor 
f418572001-07-21Martin Stjernholm  defvar("MyWorldLocation", "",
e115bf2001-08-28Per Hedbor  DLOCALE(36, "Ports: Primary Server URL"), TYPE_URL|VAR_PUBLIC,
f418572001-07-21Martin Stjernholm  DLOCALE(37, #"\ This is the main server URL, where your start page is located. This setting is for instance used as fallback to generate absolute URLs to the server, but in most circumstances the URLs sent by the clients are used. A URL is deduced from the first entry in 'URLs' if this is left blank. <p>Note that setting this doesn't make the server accessible; you must also set 'URLs'."));
434bac2000-07-14Andreas Lange 
c551f22000-07-04Per Hedbor  defvar("URLs",
9388982003-09-18Martin Stjernholm  Variable.PortList( ({"http://*/#ip=;nobind=0;"}), VAR_INITIAL|VAR_NO_DEFAULT,
3b3eac2001-09-03Martin Nilsson  DLOCALE(38, "Ports: URLs"),
55c0522001-11-07Henrik Grubbström (Grubba)  DLOCALE(373, "Bind to these URLs. You can use '*' and '?' to perform"
434bac2000-07-14Andreas Lange  " globbing (using any of these will default to binding to "
21182a2001-10-05Per Hedbor  "all IP-numbers on your machine). If you specify a IP# in " "the field it will take precedence over the hostname.")));
c5e0961999-10-04Per Hedbor 
9ac0332002-11-05Anders Johansson  defvar("InternalLoc", internal_location,
23414a2000-07-21Andreas Lange  DLOCALE(40, "Internal module resource mountpoint"),
f406ba1999-11-27Per Hedbor  TYPE_LOCATION|VAR_MORE|VAR_DEVELOPER,
23414a2000-07-21Andreas Lange  DLOCALE(41, "Some modules may want to create links to internal "
434bac2000-07-14Andreas Lange  "resources. This setting configures an internally handled " "location that can be used for such purposes. Simply select " "a location that you are not likely to use for regular "
9ac0332002-11-05Anders Johansson  "resources.")) ->add_changed_callback(lambda(object v) { internal_location = v->query(); });
483b062002-05-16Stefan Wallström 
9ac0332002-11-05Anders Johansson  defvar("SubRequestLimit", sub_req_limit,
483b062002-05-16Stefan Wallström  "Subrequest depth limit", TYPE_INT | VAR_MORE, "A limit for the number of nested sub requests for each request. "
9ac0332002-11-05Anders Johansson  "This is intented to catch unintended infinite loops when for " "example inserting files in RXML. 0 for no limit." ) ->add_changed_callback(lambda(object v) { sub_req_limit = v->query(); });
f498ed2000-07-11Martin Nilsson  // Throttling-related variables defvar("throttle", 0,
101eb52000-11-16Per Hedbor  DLOCALE(42, "Throttling: Server; Enabled"),TYPE_FLAG,
23414a2000-07-21Andreas Lange  DLOCALE(43, "If set, per-server bandwidth throttling will be enabled. "
434bac2000-07-14Andreas Lange  "It will allow you to limit the total available bandwidth for "
1dd64a2000-09-19Mattias Wingstedt  "this site.<br />Bandwidth is assigned using a Token Bucket. "
f498ed2000-07-11Martin Nilsson  "The principle under which it works is: for each byte we send we use a token. " "Tokens are added to a repository at a constant rate. When there's not enough, " "we can't transmit. When there's too many, they \"spill\" and are lost."));
199d031999-09-05Francesco Chemolli  //TODO: move this explanation somewhere on the website and just put a link.
f498ed2000-07-11Martin Nilsson  defvar("throttle_fill_rate", 102400,
101eb52000-11-16Per Hedbor  DLOCALE(44, "Throttling: Server; Average available bandwidth"),
199d031999-09-05Francesco Chemolli  TYPE_INT,
1dd64a2000-09-19Mattias Wingstedt  DLOCALE(45, "This is the average bandwidth available to this site in "
f498ed2000-07-11Martin Nilsson  "bytes/sec (the bucket \"fill rate\")."), 0, arent_we_throttling_server); defvar("throttle_bucket_depth", 1024000,
101eb52000-11-16Per Hedbor  DLOCALE(46, "Throttling: Server; Bucket Depth"), TYPE_INT,
23414a2000-07-21Andreas Lange  DLOCALE(47, "This is the maximum depth of the bucket. After a long enough period "
f498ed2000-07-11Martin Nilsson  "of inactivity, a request will get this many unthrottled bytes of data, before " "throttling kicks back in.<br>Set equal to the Fill Rate in order not to allow " "any data bursts. This value determines the length of the time over which the " "bandwidth is averaged."), 0, arent_we_throttling_server); defvar("throttle_min_grant", 1300,
101eb52000-11-16Per Hedbor  DLOCALE(48, "Throttling: Server; Minimum Grant"), TYPE_INT,
23414a2000-07-21Andreas Lange  DLOCALE(49, "When the bandwidth availability is below this value, connections will "
f498ed2000-07-11Martin Nilsson  "be delayed rather than granted minimal amounts of bandwidth. The purpose " "is to avoid sending too small packets (which would increase the IP overhead)."), 0, arent_we_throttling_server); defvar("throttle_max_grant", 14900,
101eb52000-11-16Per Hedbor  DLOCALE(50, "Throttling: Server; Maximum Grant"), TYPE_INT,
23414a2000-07-21Andreas Lange  DLOCALE(51, "This is the maximum number of bytes assigned in a single request "
f498ed2000-07-11Martin Nilsson  "to a connection. Keeping this number low will share bandwidth more evenly " "among the pending connections, but keeping it too low will increase IP " "overhead and (marginally) CPU usage. You'll want to set it just a tiny " "bit lower than any integer multiple of your network's MTU (typically 1500 " "for ethernet)."), 0, arent_we_throttling_server);
199d031999-09-05Francesco Chemolli  defvar("req_throttle", 0,
101eb52000-11-16Per Hedbor  DLOCALE(52, "Throttling: Request; Enabled"), TYPE_FLAG,
23414a2000-07-21Andreas Lange  DLOCALE(53, "If set, per-request bandwidth throttling will be enabled.")
199d031999-09-05Francesco Chemolli  );
4d16831999-11-17Per Hedbor 
199d031999-09-05Francesco Chemolli  defvar("req_throttle_min", 1024,
101eb52000-11-16Per Hedbor  DLOCALE(54, "Throttling: Request; Minimum guarranteed bandwidth"),
199d031999-09-05Francesco Chemolli  TYPE_INT,
23414a2000-07-21Andreas Lange  DLOCALE(55, "The maximum bandwidth each connection (in bytes/sec) can use is determined "
f498ed2000-07-11Martin Nilsson  "combining a number of modules. But doing so can lead to too small " "or even negative bandwidths for particularly unlucky requests. This variable " "guarantees a minimum bandwidth for each request."), 0, arent_we_throttling_request);
4d16831999-11-17Per Hedbor 
199d031999-09-05Francesco Chemolli  defvar("req_throttle_depth_mult", 60.0,
101eb52000-11-16Per Hedbor  DLOCALE(56, "Throttling: Request; Bucket Depth Multiplier"),
199d031999-09-05Francesco Chemolli  TYPE_FLOAT,
23414a2000-07-21Andreas Lange  DLOCALE(57, "The average bandwidth available for each request will be determined by "
f498ed2000-07-11Martin Nilsson  "the modules combination. The bucket depth will be determined multiplying " "the rate by this factor."), 0, arent_we_throttling_request);
4d16831999-11-17Per Hedbor 
9fbde22000-11-06Per Hedbor  defvar("404-files", ({ "404.inc" }),
55a8662000-11-20Per Hedbor  DLOCALE(307, "No such file message override files"),
9fbde22000-11-06Per Hedbor  TYPE_STRING_LIST|VAR_PUBLIC,
55a8662000-11-20Per Hedbor  DLOCALE(308,
9fbde22000-11-06Per Hedbor  "If no file match a given resource all directories above the" " wanted file is searched for one of the files in this list." "<p>\n" "As an example, if the file /foo/bar/not_there.html is " "wanted, and this list contains the default value of 404.inc," " these files will be searched for, in this order:</p><br /> " " /foo/bar/404.inc, /foo/404.inc and /404.inc." ) );
be918b2002-02-26Marcus Wellhardh  defvar("license",
66e4c02002-02-27Marcus Wellhardh  License. LicenseVariable("../license/", VAR_NO_DEFAULT,
7aa8ac2002-06-05Anders Johansson  DLOCALE(39, "License file"), DLOCALE(336, "The license file for this configuration."),
66e4c02002-02-27Marcus Wellhardh  this_object()));
be918b2002-02-26Marcus Wellhardh 
9fbde22000-11-06Per Hedbor  class NoSuchFileOverride { // compatibility with old config-files. inherit Variable.Variable; int check_visibility( RequestID id, int more_mode, int expert_mode, int devel_mode, int initial, int|void variable_in_cfif ) { return 0; } void set( string newval ) { if( search(newval,"emit source=values") == -1 ) variables[ "404-message" ]->set( newval ); } void create() { ::create( #"<nooutput><emit source=values scope=ef variable='modvar.site.404-files'> <set variable='var.base' value=''/> <emit source='path'> <append variable='var.base' value='/&_.name;'/> <set variable='var.404' value='&var.base;/&ef.value;'/> <if exists='&var.404;'> <set variable='var.errfile' from='var.404'/> </if> </emit> </emit> </nooutput><if variable='var.errfile'><eval><insert file='&var.errfile;'/></eval></if><else><eval>&modvar.site.404-message:none;</eval></else>", 0, 0, 0 ); } }; defvar("ZNoSuchFile", NoSuchFileOverride() );
3762da2004-04-17Jonas Wallden  defvar("404-message", #"<html> <head> <title>404 - Page Not Found</title> <style> .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>
94d4752000-04-05Martin Nilsson </head>
3762da2004-04-17Jonas Wallden <body bgcolor='#f2f1eb' vlink='#2331d1' alink='#f6f6ff' leftmargin='0' rightmargin='0' topmargin='0' bottommargin='0' style='margin: 0; padding: 0'>
94d4752000-04-05Martin Nilsson 
ca9c4f2004-06-21Jonas Wallden <table border='0' cellspacing='0' cellpadding='0' height='99%'>
ade3d22004-05-28Jonas Wallden  <colgroup> <col span='3' /> <col width='356' /> <col width='0*' /> </colgroup>
94d4752000-04-05Martin Nilsson  <tr>
3762da2004-04-17Jonas Wallden  <td><img src='/internal-roxen-unit' height='30' /></td> </tr><tr> <td></td> <td><img src='/internal-roxen-404' /></td> <td><img src='/internal-roxen-unit' width='30' /></td> <td valign='bottom'><img src='/internal-roxen-page-not-found-2' /></td>
ade3d22004-05-28Jonas Wallden  <td></td>
3762da2004-04-17Jonas Wallden  </tr><tr> <td><img src='/internal-roxen-unit' height='30' /></td> </tr><tr> <td colspan='3'></td>
ade3d22004-05-28Jonas Wallden  <td colspan='2'>
3762da2004-04-17Jonas Wallden  <div class='msg'>Unable to retrieve</div> <div class='url'>&page.virtfile;</div>
ade3d22004-05-28Jonas Wallden  </td> </tr><tr> <td colspan='3'></td> <td width='356'>
3762da2004-04-17Jonas Wallden  <div class='msg'>
ade3d22004-05-28Jonas Wallden  If you feel this is