24c6c12000-02-20Martin Nilsson // A vitual server's main configuration // Copyright © 1996 - 2000, Roxen IS.
ac77452001-06-13Per Hedbor constant cvs_version = "$Id: configuration.pike,v 1.435 2001/06/13 13:45:23 per 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 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" ); ADT.Table t = ADT.Table->table( summarize_table(), ({ "What", "Calls", "Time", "CPU", "t/call(ms)", "cpu/call(ms)" })); 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 
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 ) { if( strlen( data ) > max_size ) return; 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 {
8552d92001-01-13Martin Nilsson  return query("InternalLoc")+(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 } /* 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 }
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 {
e62d482000-02-29David Hedbor  foreach( registered_urls, string url )
ecd9ab2000-08-23Per Hedbor  roxen.unregister_url(url);
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(); #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  if (!--num_modules) #ifdef THREADS modules_stopped->signal() #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. { 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) { num_modules -= 17; if (num_modules) { #ifdef THREADS // Relying on the interpreter lock here. modules_stopped->wait(); #else error ("num_modules shouldn't be nonzero here when running nonthreaded.\n"); #endif } } }
9a8a152000-09-25Per Hedbor 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";
dfe0362000-03-19Martin Nilsson  string ext=myext || Roxen.extension(file);
41b77c1999-07-15David Hedbor 
14179b1997-01-29Per Hedbor  if(tmp = types_fun(ext)) { mixed tmp2,nx; if(tmp[0] == "strip") { tmp2=file/"."; if(sizeof(tmp2) > 2) nx=tmp2[-2]; if(nx && (tmp2=types_fun(nx))) tmp[0] = tmp2[0];
9be5aa1998-07-03Henrik Grubbström (Grubba)  else if(tmp2=types_fun("default")) tmp[0] = tmp2[0];
14179b1997-01-29Per Hedbor  else
9be5aa1998-07-03Henrik Grubbström (Grubba)  tmp[0]="application/octet-stream";
14179b1997-01-29Per Hedbor  }
9be5aa1998-07-03Henrik Grubbström (Grubba)  } else if(!(tmp = types_fun("default"))) { 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);
ae32d01998-03-23David Hedbor  array 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));
24fbd41999-04-21David Hedbor  if(arrayp(error)) { error[0] = "Error in map_providers(): "+error[0];
10c7e11999-12-28Martin Nilsson  report_debug(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])) { mixed error; if (arrayp(error = catch { mixed ret; if (ret = f(@args)) {
c5e0961999-10-04Per Hedbor  return ret;
d8b7721998-05-28Henrik Grubbström (Grubba)  } })) {
24fbd41999-04-21David Hedbor  error[0] = "Error in call_provider(): "+error[0]; throw(error);
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 { if(!file_extension_module_cache[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/"::";
9a629c2001-06-11Per Hedbor  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; }
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 { function f;
f3ca762000-08-19Per Hedbor // Call all logging functions
517c7e2000-09-30Per Hedbor  foreach(logger_module_cache||logger_modules(), f)
f3ca762000-08-19Per Hedbor  if( f( request_id, file ) ) return;
14179b1997-01-29Per Hedbor 
7a243b2000-08-19Per Hedbor  if( !log_function )
f3ca762000-08-19Per Hedbor  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)
3342dd2001-01-19Per Hedbor //! @note DEPRECATED COMPATIBILITY FUNCTION //!
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)
3342dd2001-01-19Per Hedbor //! @note DEPRECATED COMPATIBILITY FUNCTION //!
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)
3342dd2001-01-19Per Hedbor //! @note DEPRECATED COMPATIBILITY FUNCTION //!
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;
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 } private static int nest = 0;
10c7e11999-12-28Martin Nilsson 
14179b1997-01-29Per Hedbor #ifdef MODULE_LEVEL_SECURITY private mapping misc_cache=([]);
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) 
bc0fa02001-03-08Per Hedbor  if(!(seclevels = misc_cache[ a ])) {
3e3bab2001-01-19Per Hedbor  RoxenModule mod = Roxen.get_owning_module (a);
ab7c312000-08-12Martin Stjernholm  if(mod && mod->query_seclevels)
3b17831998-11-22Per Hedbor  misc_cache[ a ] = seclevels = ({
2b86422000-06-29Martin Stjernholm  mod->query_seclevels(), mod->query("_seclvl"),
3b17831998-11-22Per Hedbor  }); else
bc0fa02001-03-08Per Hedbor  misc_cache[ a ] = seclevels = ({0,0});
2b86422000-06-29Martin Stjernholm  }
14179b1997-01-29Per Hedbor 
bc0fa02001-03-08Per Hedbor  if(slevel && (seclevels[1] > slevel)) // "Trustlevel" to low.
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] ) 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
bc0fa02001-03-08Per Hedbor  misc_cache = ([ ]);
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 >
9a8a152000-09-25Per Hedbor static array(string) draw_saturation_bar(int hue,int brightness, int where)
fc94331997-10-25Per Hedbor {
e351dd1999-11-29Per Hedbor  Image.Image bar=Image.Image(30,256);
fc94331997-10-25Per Hedbor  for(int i=0;i<128;i++) { int j = i*2; bar->line(0,j,29,j,@hsv_to_rgb(hue,255-j,brightness)); bar->line(0,j+1,29,j+1,@hsv_to_rgb(hue,255-j,brightness)); } where = 255-where; bar->line(0,where,29,where, 255,255,255);
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;
7de44b2000-09-13Jonas Wallden  if(sscanf(from, "%*s:%d,%d,%d", hue, bright,w)==4) { array bar = draw_saturation_bar(hue, bright, w); 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))
1a89f42000-08-14Martin Stjernholm  res = sprintf("Returned redirect to %s ", 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"])
1a89f42000-08-14Martin Stjernholm  res = sprintf("Returned authentication failed: %s ",
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:
1a89f42000-08-14Martin Stjernholm  res = sprintf("Returned %d. ", 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
434bac2000-07-14Andreas Lange  res += sprintf("%d 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();
434bac2000-07-14Andreas Lange  res += sprintf("%d 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)) {
dffa222000-12-10Per Hedbor  res += sprintf(" of %s", 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 
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 //! <ref>find_internal()</ref> callbacks will be ignored. //! //! The return values 0 (no such file) and -1 (the data is a //! directory) are only returned when `no_magic' was set to 1; //! otherwise a result mapping is always generated.
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
5655dc2001-06-06Per Hedbor  #if defined(__NT__) || defined(STRIP_BSLASH) if( strlen(id->not_query ) ) { werror("a: "+id->not_query+"\n"); int ss = (<'/','\\'>)[ id->not_query[0] ]; id->not_query = combine_path("/",replace(X,"\\","/")); if( !ss ) id->not_query = id->not_query[1..]; werror("b: "+id->not_query+"\n"); } #endif
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":
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;",
a7d0342000-11-13Martin Nilsson  "type":"image/gif" ]);
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..])), "type":"image/gif" ]);
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.
8552d92001-01-13Martin Nilsson  if(!search(file, query("InternalLoc")))
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;
8552d92001-01-13Martin Nilsson  if(2==sscanf(file[strlen(query("InternalLoc"))..], "%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();
434bac2000-07-14Andreas Lange  TRACE_LEAVE(sprintf("find_internal has returned %O", fid));
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; slevel = misc_cache[ find_internal ][1]; // misc_cache from // 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 )) { array err;
a8f1b32000-01-31Per Hedbor 
5839c31999-01-22Marcus Comstedt  nest ++; err = catch { if( nest < 20 ) 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"); } }; nest = 0; 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];
41b77c1999-07-15David Hedbor  if(!search(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)) { TRACE_LEAVE(""); 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; slevel = misc_cache[ tmp[1] ][1]; // misc_cache from // 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]); 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); 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) &&
517c7e2000-09-30Per Hedbor  (tmp = file_extension_modules(loc = Roxen.extension(id->not_query, id)))) {
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;
dfe0362000-03-19Martin Nilsson  loc = 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; }
e351dd1999-11-29Per Hedbor mixed handle_request( RequestID id )
c7a5f01999-02-16Per Hedbor { function funp; mixed file;
10c7e11999-12-28Martin Nilsson  REQUEST_WERR("handle_request()");
9c19002001-02-27Per Hedbor  TIMER_START(handle_request); TIMER_START(first_modules);
517c7e2000-09-30Per Hedbor  foreach(first_module_cache||first_modules(), funp)
c7a5f01999-02-16Per Hedbor  {
10c7e11999-12-28Martin Nilsson  if(file = funp( id ))
c7a5f01999-02-16Per Hedbor  break;
cfda381999-03-28Henrik Grubbström (Grubba)  if(id->conf != this_object()) {
10c7e11999-12-28Martin Nilsson  REQUEST_WERR("handle_request(): Redirected (2)");
c7a5f01999-02-16Per Hedbor  return id->conf->handle_request(id);
cfda381999-03-28Henrik Grubbström (Grubba)  }
c7a5f01999-02-16Per Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(first_modules);
fd8b151999-05-19David Hedbor  if(!mappingp(file) && !mappingp(file = get_file(id)))
c7a5f01999-02-16Per Hedbor  { mixed ret;
9c19002001-02-27Per Hedbor  TIMER_START(last_modules);
517c7e2000-09-30Per Hedbor  foreach(last_module_cache||last_modules(), funp) if(ret = funp(id)) break;
cfda381999-03-28Henrik Grubbström (Grubba)  if (ret == 1) {
10c7e11999-12-28Martin Nilsson  REQUEST_WERR("handle_request(): Recurse");
9c19002001-02-27Per Hedbor  TIMER_END(last_modules); TIMER_END(handle_request);
c7a5f01999-02-16Per Hedbor  return handle_request(id);
cfda381999-03-28Henrik Grubbström (Grubba)  }
c7a5f01999-02-16Per Hedbor  file = ret;
9c19002001-02-27Per Hedbor  TIMER_END(last_modules);
c7a5f01999-02-16Per Hedbor  }
9c19002001-02-27Per Hedbor  TIMER_END(handle_request);
10c7e11999-12-28Martin Nilsson  REQUEST_WERR("handle_request(): Done");
9c19002001-02-27Per Hedbor  MERGE_TIMERS(roxen);
c7a5f01999-02-16Per Hedbor  return file; }
fd93022000-05-05Martin Nilsson mapping 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 //! wrapper for <ref>low_get_file()</ref>.
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;
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)) { if(res && res->file && (res2->file != res->file)) 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  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)  { array err; nest ++;
10c7e11999-12-28Martin Nilsson 
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Recursing");
f128901997-08-15Henrik Grubbström (Grubba)  file = id->not_query; err = catch { if( 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"); }; 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 { string loc;
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
517c7e2000-09-30Per Hedbor  foreach(url_modules(), function funp)
f128901997-08-15Henrik Grubbström (Grubba)  { string of = id->not_query; id->not_query = file;
434bac2000-07-14Andreas Lange  TRACE_ENTER("URL module", funp);
f128901997-08-15Henrik Grubbström (Grubba)  LOCK(funp); tmp=funp( id, file ); UNLOCK(); if(mappingp( tmp )) { id->not_query = of;
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returned 'No thanks'.");
f128901997-08-15Henrik Grubbström (Grubba)  return 0; } if(objectp( tmp )) { file = id->not_query; array err; nest ++;
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Recursing");
f128901997-08-15Henrik Grubbström (Grubba)  err = catch { if( nest < 20 ) tmp = (id->conf || this_object())->stat_file( file, id ); else error("Too deep recursion in roxen::stat_file() while mapping " +file+".\n"); }; nest = 0; if(err) throw(err);
8fd51f1998-03-01Per Hedbor  TRACE_LEAVE("");
434bac2000-07-14Andreas Lange  TRACE_LEAVE("Returning data");
f128901997-08-15Henrik Grubbström (Grubba)  return tmp; }
8fd51f1998-03-01Per Hedbor  TRACE_LEAVE("");
f128901997-08-15Henrik Grubbström (Grubba)  id->not_query = of; } #endif
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]; if((file == loc) || ((file+"/")==loc))
41d0f91998-02-20Per Hedbor  {
434bac2000-07-14Andreas Lange  TRACE_ENTER(sprintf("Location module [%s] ", loc), tmp[1]); TRACE_LEAVE("Exact match.");
41d0f91998-02-20Per Hedbor  TRACE_LEAVE("");
223fd12000-01-27Johan Sundström  return ({ 0775, -3, 0, 0, 0, 0, 0 });
41d0f91998-02-20Per Hedbor  }
10c7e11999-12-28Martin Nilsson  if(!search(file, loc))
14179b1997-01-29Per Hedbor  {
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)) {
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
14179b1997-01-29Per Hedbor  if(s=function_object(tmp[1])->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 id->misc->defines = ([ " _error":404 ]); return Roxen.http_rxml_answer( data, id, 0, "text/html" ); }
e8790b1998-02-19Per Hedbor // this is not as trivial as it sounds. Consider gtext. :-)
9a8a152000-09-25Per Hedbor array open_file(string fname, string mode, RequestID id, void|int internal_get)
e8790b1998-02-19Per Hedbor {
517c7e2000-09-30Per Hedbor  if( id->conf && (id->conf != this_object()) ) return id->conf->open_file( fname, mode, id, internal_get );
3e3bab2001-01-19Per Hedbor  Configuration oc = id->conf;
e8790b1998-02-19Per Hedbor  string oq = id->not_query; function funp;
3a4b9a1999-12-27Martin Nilsson  mapping|int(0..1) file;
cd7ea41998-12-14Peter Bortas  id->not_query = fname;
c7a5f01999-02-16Per Hedbor 
517c7e2000-09-30Per Hedbor  foreach(first_modules(), funp)
10c7e11999-12-28Martin Nilsson  if(file = funp( id ))
e8790b1998-02-19Per Hedbor  break;
517c7e2000-09-30Per Hedbor  else if(id->conf && (id->conf != oc))
e8790b1998-02-19Per Hedbor  {
517c7e2000-09-30Per Hedbor  return id->conf->open_file(fname, mode,id, internal_get);
e8790b1998-02-19Per Hedbor  } fname = id->not_query; if(search(mode, "R")!=-1) // raw (as in not parsed..) { string f; mode -= "R"; if(f = real_file(fname, id))
41d0f91998-02-20Per Hedbor  {
91d3c32001-03-12Martin Nilsson  // report_debug("opening "+fname+" in raw mode.\n");
e8790b1998-02-19Per Hedbor  return ({ open(f, mode), ([]) });
41d0f91998-02-20Per Hedbor  }
2380831998-02-22Per Hedbor // return ({ 0, (["error":302]) });
e8790b1998-02-19Per Hedbor  } if(mode=="r") { if(!file) {
517c7e2000-09-30Per Hedbor  file = get_file( id, 0, internal_get );
f920ce1998-10-02Henrik Grubbström (Grubba)  if(!file) {
517c7e2000-09-30Per Hedbor  foreach(last_modules(), funp) if(file = funp( id ))
e8790b1998-02-19Per Hedbor  break;
f920ce1998-10-02Henrik Grubbström (Grubba)  if (file == 1) { // Recurse.
484ec92000-06-23Martin Stjernholm  return open_file(id->not_query, mode, id, internal_get);
f920ce1998-10-02Henrik Grubbström (Grubba)  } }
e8790b1998-02-19Per Hedbor  } if(!mappingp(file)) { if(id->misc->error_code)
dfe0362000-03-19Martin Nilsson  file = Roxen.http_low_answer(id->misc->error_code, "Failed" );
2380831998-02-22Per Hedbor  else if(id->method!="GET"&&id->method != "HEAD"&&id->method!="POST")
dfe0362000-03-19Martin Nilsson  file = Roxen.http_low_answer(501, "Not implemented.");
73ce3d2000-12-11Per Hedbor  else file = error_file( id );
e8790b1998-02-19Per Hedbor  id->not_query = oq;
10c7e11999-12-28Martin Nilsson 
e8790b1998-02-19Per Hedbor  return ({ 0, file }); }
10c7e11999-12-28Martin Nilsson  if( file->data )
e8790b1998-02-19Per Hedbor  { file->file = StringFile(file->data); m_delete(file, "data");
10c7e11999-12-28Martin Nilsson  }
e8790b1998-02-19Per Hedbor  id->not_query = oq; return ({ file->file, file }); } id->not_query = oq;
23414a2000-07-21Andreas Lange  return ({ 0, (["error":501, "data":"Not implemented." ]) });
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 )) { array err; nest ++;
10c7e11999-12-28Martin Nilsson 
a86c6c1997-09-22Henrik Grubbström (Grubba)  file = id->not_query; err = catch { if( nest < 20 ) 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)  }; nest = 0; 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 if(check_security(tmp[1], id)) continue; #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; } } }
10c7e11999-12-28Martin Nilsson int|string try_get_file(string s, RequestID id,
646f722000-03-07Martin Stjernholm  int|void status, int|void nocache, int|void not_internal)
2688e22000-07-26Johan Sundström //! 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.
14179b1997-01-29Per Hedbor {
646f722000-03-07Martin Stjernholm  string res, q, cache_key;
e351dd1999-11-29Per Hedbor  RequestID fake_id;
14179b1997-01-29Per Hedbor  mapping m;
10c7e11999-12-28Martin Nilsson  if(!objectp(id))
14179b1997-01-29Per Hedbor  error("No ID passed to 'try_get_file'\n");
e351dd1999-11-29Per Hedbor  // id->misc->common makes it possible to pass information to // the originating request. if ( !id->misc ) id->misc = ([]); if ( !id->misc->common ) id->misc->common = ([]);
10c7e11999-12-28Martin Nilsson 
e351dd1999-11-29Per Hedbor  fake_id = id->clone_me();
10c7e11999-12-28Martin Nilsson 
e351dd1999-11-29Per Hedbor  fake_id->misc->common = id->misc->common;
484ec92000-06-23Martin Stjernholm  fake_id->misc->internal_get = !not_internal;
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;
c927a02000-03-18Martin Stjernholm  if(!(m = get_file(fake_id,0,!not_internal))) {
4cd5e82000-03-20Martin Stjernholm  // Might be a PATH_INFO type URL. m_delete (fake_id->misc, "path_info");
484ec92000-06-23Martin Stjernholm  array a = open_file( s, "r", fake_id, !not_internal );
e1e86d2000-03-20Martin Stjernholm  if(a && a[0]) { m = a[1]; 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 
3bb38c2000-01-20Martin Bähr  if (!mappingp(m) && !objectp(m)) { report_error("try_get_file(%O, %O, %O, %O): m = %O is not a mapping.\n", s, id, status, nocache, m); return 0; }
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 
3510fb1997-11-09Henrik Grubbström (Grubba)  if(status) return 1;
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();
14179b1997-01-29Per Hedbor  destruct(m->file); 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; }
9fd8092000-08-08Johan Sundström int(0..1) is_file(string virt_path, RequestID id) //! Is `virt_path' a file in our virtual filesystem?
14179b1997-01-29Per Hedbor {
9fd8092000-08-08Johan Sundström  return !!stat_file(virt_path, id);
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) {
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 });
03aa492000-08-23Per Hedbor  roxen.unregister_url( url );
5d6c8d2000-09-01Per Hedbor  }
ecd9ab2000-08-23Per Hedbor 
03aa492000-08-23Per Hedbor  failed_urls = ({ });
ecd9ab2000-08-23Per Hedbor 
8514832000-11-27Per Hedbor  int st = gethrtime();
5d6c8d2000-09-01Per Hedbor  foreach( (query( "URLs" )-registered_urls), string url )
ecd9ab2000-08-23Per Hedbor  if( roxen.register_url( url, this_object() ) ) registered_urls += ({ url });
03aa492000-08-23Per Hedbor  else failed_urls += ({ url });
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;
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 
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] );
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 
b86de82000-11-13Per Hedbor  if( !old_module->fake ) { save_one( old_module ); master()->refresh_inherit( object_program( old_module ) ); master()->refresh( object_program( old_module ), 1 ); }
2f79202000-03-27Per Hedbor  catch( disable_module( modname, 1 ) );
f569581999-11-23Per Hedbor 
2f79202000-03-27Per Hedbor  RoxenModule nm;
bcf5662000-04-05Per Hedbor  if( catch( nm = enable_module( modname, 0, 0, 1 ) ) || (nm == 0) ) enable_module( modname, (nm=old_module), mi, 1 );
ee3ff02000-04-06Per Hedbor  else {
2e597a2000-04-06Martin Stjernholm  foreach ((array) old_module->error_log, [string msg, array(int) times]) nm->error_log[msg] += times;
ee3ff02000-04-06Per Hedbor 
b86de82000-11-13Per Hedbor  ModuleInfo mi = roxen.find_module( (modname/"#")[0] );
ee3ff02000-04-06Per Hedbor  catch( mi->update_with( nm,0 ) ); // This is sort of nessesary...
8148ed2000-09-13Andreas Lange  nm->report_notice(LOC_C(11, "Reloaded %s.")+"\n", mi->get_name());
1dd64a2000-09-19Mattias Wingstedt  // It's possible e.g. in the admin interface that the module
ab7c312000-08-12Martin Stjernholm  // being reloaded is in use for the current request, so delay it a // little.
637a122000-09-01Martin Stjernholm  //call_out (destruct, 2, old_module); // Nope, can't do that since there are things like lookup caches // that count on that the old module object is gone before the new // is started. destruct (old_module);
2e597a2000-04-06Martin Stjernholm  }
bcf5662000-04-05Per Hedbor  call_start_callbacks( nm, mi, modules[ (modname/"#")[0] ] );
f569581999-11-23Per Hedbor 
2f79202000-03-27Per Hedbor  return nm;
5964251999-11-19Per Hedbor }
beba572000-03-20Martin Stjernholm #ifdef THREADS Thread.Mutex enable_modules_mutex = Thread.Mutex(); #define MODULE_LOCK \ Thread.MutexKey enable_modules_lock = enable_modules_mutex->lock (2) #else #define MODULE_LOCK #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, int|void nostart )
14179b1997-01-29Per Hedbor {
beba572000-03-20Martin Stjernholm  MODULE_LOCK;
c5e0961999-10-04Per Hedbor  int id;
e351dd1999-11-29Per Hedbor  ModuleCopies module;
c5e0961999-10-04Per Hedbor  int pr; mixed err; int module_type;
8b16fe2000-09-05Per Hedbor 
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 
7f00081998-03-20Per Hedbor  int start_time = gethrtime();
25171c1999-11-06Per Hedbor 
2f79202000-03-27Per Hedbor  if( !moduleinfo )
ad683e1998-05-09Henrik Grubbström (Grubba)  {
9a8a152000-09-25Per Hedbor  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;
2f79202000-03-27Per Hedbor  return 0; }
c5e0961999-10-04Per Hedbor  }
9a1d472000-01-12Martin Stjernholm  string descr = moduleinfo->get_name() + (id ? " copy " + (id + 1) : "");
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;
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  {
c45e3f2000-02-16Per Hedbor  if( module[id]->stop )
0d1e432000-11-02Per Hedbor  catch( module[id]->stop() );
f569581999-11-23Per Hedbor // if( err = catch( disable_module( modname+"#"+id ) ) ) // report_error(LOCALE->error_disabling_module(moduleinfo->get_name(), // describe_backtrace(err)));
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|
f590762000-09-10Martin Nilsson  MODULE_FILTER|MODULE_TAG|MODULE_FIRST))
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})); }) { throw(err); }
3b17831998-11-22Per Hedbor  }
10c7e11999-12-28Martin Nilsson 
21306c2000-11-02Per Hedbor #ifdef MODULE_LEVEL_SECURITY if( (module_type & ~(MODULE_LOGGER|MODULE_PROVIDER)) != 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 " " value (monday=1, sunday=7) or a string (monday, thuesday etc)</dd>" "</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 if (enable_module_batch_msgs) report_debug("\bOK %6.1fms\n", (gethrtime()-start_time)/1000.0); #endif
fd24e22000-08-28Per Hedbor  if( !enabled_modules[modname+"#"+id] ) { enabled_modules[modname+"#"+id] = 1; store( "EnabledModules", enabled_modules, 1, this_object()); }
6f595f2000-08-20Per Hedbor 
bcf5662000-04-05Per Hedbor  if (!has_stored_vars) 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 
bcf5662000-04-05Per Hedbor  return me; } void call_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  call_low_start_callbacks( me, moduleinfo, module );
ad683e1998-05-09Henrik Grubbström (Grubba)  mixed err;
c5e0961999-10-04Per Hedbor  if((me->start) && (err = catch( me->start(0, this_object()) ) ) ) { #ifdef MODULE_DEBUG
bcf5662000-04-05Per Hedbor  if (enable_module_batch_msgs) report_debug("\bERROR\n");
c5e0961999-10-04Per Hedbor #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"));
f63aca2000-09-08Martin Stjernholm  got_no_delayed_load = -1;
ad683e1998-05-09Henrik Grubbström (Grubba)  /* Clean up some broken references to this module. */
bcf5662000-04-05Per Hedbor // m_delete(otomod, me); // m_delete(module->copies, search( module->copies, me )); // destruct(me); // return 0;
ad683e1998-05-09Henrik Grubbström (Grubba)  }
5ffa542000-02-16Per Hedbor  if( inited && me->ready_to_receive_requests )
bcf5662000-04-05Per Hedbor  if( mixed q = catch( me->ready_to_receive_requests( this_object() ) ) ) {
c2fdff2000-03-21Martin Stjernholm #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 ) );
f63aca2000-09-08Martin Stjernholm  got_no_delayed_load = -1;
c2fdff2000-03-21Martin Stjernholm  }
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 )
10c7e11999-12-28Martin Nilsson  if(pri[pr]->file_extension_modules[foo] )
ad683e1998-05-09Henrik Grubbström (Grubba)  pri[pr]->file_extension_modules[foo]+=({me}); else pri[pr]->file_extension_modules[foo]=({me}); }
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  {
ad683e1998-05-09Henrik Grubbström (Grubba)  mixed provs = me->query_provides(); 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 }
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;
199d031999-09-05Francesco Chemolli  case "throttle": if (value) { THROTTLING_DEBUG("configuration: Starting throttler up"); throttler=.throttler(); throttler->throttle(query("throttle_fill_rate"), query("throttle_bucket_depth"), query("throttle_min_grant"), query("throttle_max_grant")); } else {
7e0f382000-05-06Francesco Chemolli  if (throttler) { //check, or get a backtrace the first time it's set THROTTLING_DEBUG("configuration: Stopping throttler"); destruct(throttler); throttler=0; }
199d031999-09-05Francesco Chemolli  } return 0; case "throttle_fill_rate": case "throttle_bucket_depth": case "throttle_min_grant": case "throttle_max_grant": THROTTLING_DEBUG("configuration: setting throttling parameter: "+ name+"="+value); throttler->throttle(query("throttle_fill_rate"), query("throttle_bucket_depth"), query("throttle_min_grant"), query("throttle_max_grant")); return 0;
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 ) { MODULE_LOCK; 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 
6f595f2000-08-20Per Hedbor  m_delete( enabled_modules, modname + "#" + id ); forcibly_added[ modname + "#" + id ] = 0;
5fbaec2001-04-11Per Hedbor  if( !nodest ) { 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 //! module.
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; }
f5a2741999-10-18Per Hedbor multiset forcibly_added = (<>); 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
9a1d472000-01-12Martin Stjernholm  forcibly_added[ mod+"#0" ] = 1; enable_module( mod+"#0" );
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 = ([]);
ed93131998-07-09Johan Schön mapping sql_cache = ([]);
850c282001-01-10Per Hedbor Sql.Sql sql_cache_get(string what)
ed93131998-07-09Johan Schön { #ifdef THREADS if(sql_cache[what] && sql_cache[what][this_thread()]) return sql_cache[what][this_thread()]; if(!sql_cache[what])
850c282001-01-10Per Hedbor  sql_cache[what] = ([ this_thread():Sql.Sql( what ) ]);
ed93131998-07-09Johan Schön  else
850c282001-01-10Per Hedbor  sql_cache[what][ this_thread() ] = Sql.Sql( what );
ed93131998-07-09Johan Schön  return sql_cache[what][ this_thread() ]; #else /* !THREADS */ if(!sql_cache[what])
850c282001-01-10Per Hedbor  sql_cache[what] = Sql.Sql( what );
ed93131998-07-09Johan Schön  return sql_cache[what]; #endif }
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 
1dd64a2000-09-19Mattias Wingstedt // This is the most likely URL for a site.
14179b1997-01-29Per Hedbor private string get_my_url() { string s;
c79b261998-02-05Johan Schön #if efun(gethostname)
14179b1997-01-29Per Hedbor  s = (gethostname()/".")[0] + "." + query("Domain"); s -= "\n";
c79b261998-02-05Johan Schön #else s = "localhost"; #endif
14179b1997-01-29Per Hedbor  return "http://" + s + "/"; }
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;
f63aca2000-09-08Martin Stjernholm // 0 -> enabled delayed loading, 1 -> disable delayed loading, // -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() { MODULE_LOCK; 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 
d53f0b2000-09-09Martin Stjernholm  if (!modules_already_enabled) { enabled_modules = retrieve("EnabledModules", this_object());
3e3bab2001-01-19Per Hedbor  roxenloader.LowErrorContainer ec = roxenloader.LowErrorContainer();
d53f0b2000-09-09Martin Stjernholm  roxenloader.push_compile_error_handler( ec ); array modules_to_process = indices( enabled_modules ); string tmp_string; array err; forcibly_added = (<>); enable_module_batch_msgs = 1; foreach( modules_to_process, tmp_string ) { if( !forcibly_added[ tmp_string ] ) if(err = catch( enable_module( tmp_string ))) { report_error(LOC_M(45, "Failed to enable the module %s. Skipping.\n%s"), tmp_string, describe_backtrace(err)); got_no_delayed_load = -1; } } enable_module_batch_msgs = 0; roxenloader.pop_compile_error_handler(); if( strlen( ec->get() ) ) report_error( "While enabling modules in "+name+":\n"+ec->get() ); if( strlen( ec->get_warnings() ) ) report_warning( "While enabling modules in "+name+":\n"+ec->get_warnings());
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);
0f28da1997-08-13Per Hedbor }
5f6dae2000-08-13Per Hedbor DataCache datacache;
9a8a152000-09-25Per Hedbor static void create(string config)
0f28da1997-08-13Per Hedbor {
14179b1997-01-29Per Hedbor  name=config;
8514832000-11-27Per Hedbor // int st = gethrtime();
55a8662000-11-20Per Hedbor  roxen.add_permission( "Site:"+config, LOC_C(306,"Site")+": "+config );
62e1bb2000-11-08Per Hedbor 
b0a9ea2001-04-18Martin Stjernholm  // for now only these two. In the future there might be more variables.
a3be8e2000-10-06Martin Stjernholm  defvar( "data_cache_size", 2048, 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"));
a3be8e2000-10-06Martin Stjernholm  defvar( "data_cache_file_max_size", 50, 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 "
5f6dae2000-08-13Per Hedbor  "the cache"));
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"),
e4e6d32000-11-02Per Hedbor  TYPE_STRING|VAR_MORE| VAR_PUBLIC,
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 ( "", roxen.compat_levels, 0,
89d1d82001-05-16Martin Nilsson  DLOCALE(246, "Compatibility level"),
b0a9ea2001-04-18Martin Stjernholm  DLOCALE(0, ""))); set ("compat_level", roxen.__roxen_version__);
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,
23414a2000-07-21Andreas Lange  DLOCALE(27, "What format to use for logging. The syntax is:\n"
14179b1997-01-29Per Hedbor  "<pre>"
434bac2000-07-14Andreas Lange  "response-code or *: Log format for that response code\n\n"
14179b1997-01-29Per Hedbor  "Log format is normal characters, or one or more of the " "variables below:\n" "\n" "\\n \\t \\r -- As in C, newline, tab and linefeed\n" "$char(int) -- Insert the (1 byte) character specified by the integer.\n" "$wchar(int) -- Insert the (2 byte) word specified by the integer.\n" "$int(int) -- Insert the (4 byte) word specified by the integer.\n" "$^ -- Supress newline at the end of the logentry\n" "$host -- The remote host name, or ip number.\n"
f034ab2001-04-17Per Hedbor  "$vhost -- The Host request-header sent by the client, or - if none\n"
14179b1997-01-29Per Hedbor  "$ip_number -- The remote ip number.\n" "$bin-ip_number -- The remote host id as a binary integer number.\n" "\n" "$cern_date -- Cern Common Log file format date.\n"
434bac2000-07-14Andreas Lange  "$bin-date -- Time, but as an 32 bit integer in network byteorder\n"
14179b1997-01-29Per Hedbor  "\n" "$method -- Request method\n" "$resource -- Resource identifier\n"
dfb4ec1999-05-20Francesco Chemolli  "$full_resource -- Full requested resource, including any query fields\n"
14179b1997-01-29Per Hedbor  "$protocol -- The protocol used (normally HTTP/1.0)\n" "$response -- The response code sent\n" "$bin-response -- The response code sent as a binary short number\n" "$length -- The length of the data section of the reply\n"
434bac2000-07-14Andreas Lange  "$bin-length -- Same, but as an 32 bit integer in network byteorder\n"
0bf5a11998-04-03Henrik Grubbström (Grubba)  "$request-time -- The time the request took (seconds)\n"
14179b1997-01-29Per Hedbor  "$referer -- the header 'referer' from the request, or '-'.\n"
f498ed2000-07-11Martin Nilsson  "$user_agent -- the header 'User-Agent' from the request, or '-'.\n\n"
14179b1997-01-29Per Hedbor  "$user -- the name of the auth user used, if any\n" "$user_id -- A unique user ID, if cookies are supported,\n" " by the client, otherwise '0'\n"
f498ed2000-07-11Martin Nilsson  "</pre>"), 0, lambda(){ return !query("Log");});
b796b51998-11-18Per Hedbor 
23414a2000-07-21Andreas Lange  defvar("Log", 1, DLOCALE(28, "Logging: Enabled"), TYPE_FLAG, DLOCALE(29, "Log requests"));
14179b1997-01-29Per 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"), TYPE_STRING|VAR_PUBLIC,
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 
1acaeb2000-04-06Per Hedbor  defvar("MyWorldLocation", "http://"+gethostname()+"/",
e4e6d32000-11-02Per Hedbor  DLOCALE(36, "Primary Server URL"), TYPE_URL|VAR_PUBLIC,
23414a2000-07-21Andreas Lange  DLOCALE(37, "This is the main server URL, where your start page is "
434bac2000-07-14Andreas Lange  "located. Please note that you also have to configure the " "'URLs' variable."));
c551f22000-07-04Per Hedbor  defvar("URLs", Variable.PortList( ({"http://*/"}), VAR_INITIAL,
23414a2000-07-21Andreas Lange  DLOCALE(38, "URLs"), DLOCALE(39, "Bind to these URLs. You can use '*' and '?' to perform"
434bac2000-07-14Andreas Lange  " globbing (using any of these will default to binding to " "all IP-numbers on your machine). The possible protocols " "are http, fhttp (a faster version of the normal HTTP " "protocol, but not 100% compatible with all modules) " "https, ftp, ftps, gopher and tetris.")));
c5e0961999-10-04Per Hedbor 
199d031999-09-05Francesco Chemolli  defvar("InternalLoc", "/_internal/",
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 " "resources."));
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." ) ); 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() ); defvar("404-message", #"
94d4752000-04-05Martin Nilsson <html><head> <title>404 - Page not found</title> </head> <body alink=\"#000000\" bgcolor=\"#ffffff\" bottommargin=\"0\" leftmargin=\"0\" link=\"#ce5c00\" marginheight=\"2\" marginwidth=\"0\" rightmargin=\"0\" text=\"#333333\" topmargin=\"2\" vlink=\"#ce5c00\">
8cf9d82000-09-19Martin Nilsson <if nserious=''><set variable='var.404' value='-sorry' /></if>
94d4752000-04-05Martin Nilsson <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\"> <tr>
8cf9d82000-09-19Martin Nilsson  <td><img src=\"/internal-roxen-page-not-found&var.404;\" border=\"0\" alt=\"Page not found\" width=\"404\" hspace=\"2\" /></td>
94d4752000-04-05Martin Nilsson  <td>&nbsp;</td>
8cf9d82000-09-19Martin Nilsson  <td align=\"right\"><font face=\"lucida,helvetica,arial\">
59a0492000-12-11Martin Nilsson  <b>Roxen WebServer &roxen.base-version;&nbsp;</b></font></td>
94d4752000-04-05Martin Nilsson  </tr> <tr> <td width=\"100%\" height=\"21\" colspan=\"3\" background=\"/internal-roxen-tile\"><img src=\"/internal-roxen-unit\" alt=\"\" /></td> </tr> </table> <font face=\"lucida,helvetica,arial\"> <h2>&nbsp;Unable to retrieve &page.virtfile;.</h2> <br /><br /> <blockquote> If you feel that this is a configuration error,
8cf9d82000-09-19Martin Nilsson please contact the administrators of this webserver or the author of the <if referrer=''>
94d4752000-04-05Martin Nilsson <a href=\"&client.referrer;\">referring</a> </if><else> referring </else> page. </blockquote> </font> </body> ",
9fbde22000-11-06Per Hedbor  DLOCALE(58, "No such file message"), TYPE_TEXT_FIELD|VAR_PUBLIC,
23414a2000-07-21Andreas Lange  DLOCALE(59, "What to return when there is no resource or file "
434bac2000-07-14Andreas Lange  "available at a certain location."));
a7e39f2000-02-04Per Hedbor 
e4e6d32000-11-02Per Hedbor  definvisvar( "no_delayed_load", 0, TYPE_FLAG|VAR_PUBLIC );
a7e39f2000-02-04Per Hedbor 
91d3c32001-03-12Martin Nilsson // report_debug("[defvar: %.1fms] ", (gethrtime()-st)/1000.0 );
8514832000-11-27Per Hedbor // st = gethrtime();
b0a9ea2001-04-18Martin Stjernholm  mapping(string:mixed) retrieved_vars = retrieve("spider#0", this_object()); if (sizeof (retrieved_vars) && !retrieved_vars->compat_level) // Upgrading an older configuration; default to 2.1 compatibility level. set ("compat_level", "2.1"); setvars( retrieved_vars );
199d031999-09-05Francesco Chemolli 
91d3c32001-03-12Martin Nilsson // report_debug("[restore: %.1fms] ", (gethrtime()-st)/1000.0 );
07c9921999-11-23Per Hedbor  if (query("throttle"))
c5e0961999-10-04Per Hedbor  {
199d031999-09-05Francesco Chemolli  throttler=.throttler(); throttler->throttle(query("throttle_fill_rate"), query("throttle_bucket_depth"), query("throttle_min_grant"), query("throttle_max_grant")); } }
9a8a152000-09-25Per Hedbor static int arent_we_throttling_server () {
199d031999-09-05Francesco Chemolli  return !query("throttle"); }
9a8a152000-09-25Per Hedbor static int arent_we_throttling_request() {
199d031999-09-05Francesco Chemolli  return !query("req_throttle");
14179b1997-01-29Per Hedbor }