|
|
|
#include <stat.h> |
#include <config.h> |
#include <module.h> |
#include <module_constants.h> |
constant cvs_version="$Id: prototypes.pike,v 1.233 2009/02/23 17:30:03 mast Exp $"; |
|
#ifdef DAV_DEBUG |
#define DAV_WERROR(X...) werror(X) |
#else /* !DAV_DEBUG */ |
#define DAV_WERROR(X...) |
#endif /* DAV_DEBUG */ |
|
#ifdef VARY_DEBUG |
#define VARY_WERROR(X...) werror("VARY: " + X) |
#else |
#define VARY_WERROR(X...) |
#endif /* VARY_DEBUG */ |
|
|
|
object Roxen; |
|
|
|
constant ignore_identifiers = (< |
"cvs_version", "Roxen", "ignore_identifiers" |
>); |
|
protected class Variable |
{ |
constant is_variable = 1; |
constant type = "Basic"; |
|
string get_warnings(); |
int get_flags(); |
void set_flags( int flags ); |
int check_visibility( RequestID id, |
int more_mode, |
int expert_mode, |
int devel_mode, |
int initial, |
int|void variable_in_cfif ); |
void set_invisibility_check_callback( function(RequestID,Variable:int) cb ); |
function(Variable:void) get_changed_callback( ); |
void set_changed_callback( function(Variable:void) cb ); |
void add_changed_callback( function(Variable:void) cb ); |
function(RequestID,Variable:int) get_invisibility_check_callback() ; |
string doc( ); |
string name( ); |
string type_hint( ); |
mixed default_value(); |
void set_warning( string to ); |
int set( mixed to ); |
int low_set( mixed to ); |
mixed query(); |
int is_defaulted(); |
array(string|mixed) verify_set( mixed new_value ); |
mapping(string:string) get_form_vars( RequestID id ); |
mixed transform_from_form( string what ); |
void set_from_form( RequestID id ); |
string path(); |
void set_path( string to ); |
string render_form( RequestID id, void|mapping additional_args ); |
string render_view( RequestID id ); |
} |
|
class BasicDefvar |
{ |
mapping(string:Variable) variables=([]); |
Variable getvar( string name ); |
int deflocaledoc( string locale, string variable, |
string name, string doc, mapping|void translate ); |
void set(string var, mixed value); |
int killvar(string var); |
void setvars( mapping (string:mixed) vars ); |
Variable defvar(string var, mixed value, |
mapping|string|void|object name, |
int|void type, |
mapping|string|void|object doc_str, |
mixed|void misc, |
int|function|void not_in_config, |
mapping|void option_translations); |
mixed query(string|void var, int|void ok); |
void definvisvar(string name, mixed value, int type, array|void misc); |
} |
|
|
|
class StringFile( string data, mixed|void _st ) |
{ |
int offset; |
|
string _sprintf() |
{ |
return "StringFile("+strlen(data)+","+offset+")"; |
} |
|
string read(int nbytes) |
{ |
if(!nbytes) |
{ |
offset = strlen(data); |
return data; |
} |
string d = data[offset..offset+nbytes-1]; |
offset += strlen(d); |
return d; |
} |
|
array stat() |
{ |
if( _st ) return (array)_st; |
return ({ 0, strlen(data), time(), time(), time(), 0, 0, 0 }); |
} |
|
void write(mixed ... args) |
{ |
throw( ({ "File not open for write\n", backtrace() }) ); |
} |
|
void seek(int to) |
{ |
offset = to; |
} |
|
void set_blocking() |
{ |
} |
} |
|
class ModuleInfo |
{ |
string sname; |
string filename; |
|
int last_checked; |
int type, multiple_copies; |
array(string) locked; |
mapping(Configuration:int) config_locked; |
|
string get_name(); |
string get_description(); |
RoxenModule instance( object conf, void|int silent ); |
void save(); |
void update_with( RoxenModule mod, string what ); |
int init_module( string what ); |
int find_module( string sn ); |
int check (void|int force); |
} |
|
class ModuleCopies |
{ |
mapping copies = ([]); |
mixed `[](mixed q ) |
{ |
return copies[q]; |
} |
mixed `[]=(mixed q,mixed w ) |
{ |
return copies[q]=w; |
} |
array _indices() |
{ |
return indices(copies); |
} |
array _values() |
{ |
return values(copies); |
} |
string _sprintf( ) { return "ModuleCopies("+sizeof(copies)+")"; } |
} |
|
|
protected constant SimpleNode = Parser.XML.Tree.SimpleNode; |
protected constant SimpleRootNode = Parser.XML.Tree.SimpleRootNode; |
protected constant SimpleHeaderNode = Parser.XML.Tree.SimpleHeaderNode; |
protected constant SimpleTextNode = Parser.XML.Tree.SimpleTextNode; |
protected constant SimpleElementNode = Parser.XML.Tree.SimpleElementNode; |
|
|
|
|
|
|
|
|
|
|
class DAVLock |
{ |
string locktoken; |
|
|
|
|
|
string path; |
|
|
|
int(0..1) recursive; |
|
|
|
string|SimpleNode lockscope; |
|
|
|
|
|
|
|
|
string|SimpleNode locktype; |
|
|
|
|
|
|
|
int(0..) expiry_delta; |
|
|
|
|
|
array(SimpleNode) owner; |
|
|
|
|
|
|
|
int(0..) expiry_time; |
|
|
|
|
|
protected void create(string locktoken, string path, int(0..1) recursive, |
string|SimpleNode lockscope, string|SimpleNode locktype, |
int(0..) expiry_delta, array(SimpleNode) owner) |
{ |
DAVLock::locktoken = locktoken; |
DAVLock::path = path; |
DAVLock::recursive = recursive; |
DAVLock::lockscope = lockscope; |
DAVLock::locktype = locktype; |
DAVLock::expiry_delta = expiry_delta; |
DAVLock::owner = owner; |
if (expiry_delta) { |
if (expiry_delta < 0) error("Negative expiry delta!\n"); |
expiry_time = time() + expiry_delta; |
} |
} |
|
|
|
SimpleNode get_xml() |
{ |
SimpleElementNode res = SimpleElementNode("DAV:activelock", ([]))-> |
add_child(SimpleElementNode("DAV:locktype", ([]))-> |
add_child(stringp(locktype)? |
SimpleElementNode(locktype, ([])):locktype))-> |
add_child(SimpleElementNode("DAV:lockscope", ([]))-> |
add_child(stringp(lockscope)? |
SimpleElementNode(lockscope, ([])):lockscope))-> |
add_child(SimpleElementNode("DAV:depth", ([]))-> |
add_child(recursive? |
SimpleTextNode("Infinity"):SimpleTextNode("0"))); |
|
if (owner) { |
SimpleElementNode node; |
res->add_child(node = SimpleElementNode("DAV:owner", ([]))); |
node->replace_children(owner); |
} |
|
if (expiry_delta) { |
res->add_child(SimpleElementNode("DAV:timeout", ([]))-> |
add_child(SimpleTextNode(sprintf("Second-%d", |
expiry_delta)))); |
} else { |
res->add_child(SimpleElementNode("DAV:timeout", ([]))-> |
add_child(SimpleTextNode("Infinite"))); |
} |
|
res->add_child(SimpleElementNode("DAV:locktoken", ([]))-> |
add_child(SimpleElementNode("DAV:href", ([]))-> |
add_child(SimpleTextNode(locktoken)))); |
|
return res; |
} |
|
protected string _sprintf (int flag) |
{ |
return flag == 'O' && |
sprintf ("DAVLock(%O on %O, %s, %s%s)", locktoken, path, |
recursive ? "rec" : "norec", |
lockscope == "DAV:exclusive" ? "excl" : |
lockscope == "DAV:shared" ? "shared" : |
sprintf ("%O", lockscope), |
locktype == "DAV:write" ? "" : sprintf (", %O", locktype)); |
} |
} |
|
|
|
|
|
class Configuration |
{ |
inherit BasicDefvar; |
constant is_configuration = 1; |
mapping enabled_modules = ([]); |
mapping(string:array(int)) error_log=([]); |
|
#ifdef PROFILE |
mapping(string:array(int)) profile_map = ([]); |
#endif |
|
class Priority |
{ |
string _sprintf() |
{ |
return "Priority()"; |
} |
|
array (RoxenModule) url_modules = ({ }); |
array (RoxenModule) logger_modules = ({ }); |
array (RoxenModule) location_modules = ({ }); |
array (RoxenModule) filter_modules = ({ }); |
array (RoxenModule) last_modules = ({ }); |
array (RoxenModule) first_modules = ({ }); |
mapping (string:array(RoxenModule)) file_extension_modules = ([ ]); |
mapping (RoxenModule:multiset(string)) provider_modules = ([ ]); |
} |
|
class DataCache |
{ |
int current_size, max_size, max_file_size; |
int hits, misses; |
void flush(); |
void expire_entry(string url, RequestID id); |
void set(string url, string data, mapping meta, int expire, RequestID id); |
array(string|mapping(string:mixed)) get(string url, RequestID id); |
void init_from_variables( ); |
}; |
|
array(Priority) allocate_pris(); |
|
object throttler; |
RoxenModule types_module; |
RoxenModule dir_module; |
function types_fun; |
|
string name; |
int inited; |
|
|
int requests, sent, hsent, received; |
|
function(string:int) log_function; |
DataCache datacache; |
|
int get_config_id(); |
string get_doc_for( string region, string variable ); |
string query_internal_location(RoxenModule|void mod); |
string query_name(); |
string comment(); |
void unregister_urls(); |
void stop(void|int asynch); |
string|array(string) type_from_filename( string file, int|void to, |
string|void myext ); |
|
string get_url(); |
|
array (RoxenModule) get_providers(string provides); |
RoxenModule get_provider(string provides); |
array(mixed) map_providers(string provides, string fun, mixed ... args); |
mixed call_provider(string provides, string fun, mixed ... args); |
array(function) file_extension_modules(string ext); |
array(function) url_modules(); |
mapping api_functions(void|RequestID id); |
array(function) logger_modules(); |
array(function) last_modules(); |
array(function) first_modules(); |
array location_modules(); |
array(function) filter_modules(); |
void init_log_file(); |
int|mapping check_security(function|object a, RequestID id, void|int slevel); |
void invalidate_cache(); |
void clear_memory_caches(); |
string examine_return_mapping(mapping m); |
multiset(DAVLock) find_locks(string path, int(0..1) recursive, |
int(0..1) exclude_shared, RequestID id); |
DAVLock|LockFlag check_locks(string path, int(0..1) recursive, RequestID id); |
mapping(string:mixed) unlock_file(string path, DAVLock lock, RequestID|int(0..0) id); |
int expire_locks(RequestID id); |
void refresh_lock(DAVLock lock); |
mapping(string:mixed)|DAVLock lock_file(string path, |
int(0..1) recursive, |
string lockscope, |
string locktype, |
int(0..) expiry_delta, |
array(Parser.XML.Tree.Node) owner, |
RequestID id); |
mapping|int(-1..0) low_get_file(RequestID id, int|void no_magic); |
mapping get_file(RequestID id, int|void no_magic, int|void internal_get); |
array(string) find_dir(string file, RequestID id, void|int(0..1) verbose); |
array(int)|object(Stdio.Stat) stat_file(string file, RequestID id); |
array open_file(string fname, string mode, RequestID id, void|int ig, void|int rc); |
mapping(string:array(mixed)) find_dir_stat(string file, RequestID id); |
array access(string file, RequestID id); |
string real_file(string file, RequestID id); |
int|string try_get_file(string s, RequestID id, |
int|void status, int|void nocache, |
int|void not_internal, mapping|void result_mapping); |
int(0..1) is_file(string virt_path, RequestID id, int(0..1)|void internal); |
void start(int num); |
void save_me(); |
int save_one( RoxenModule o ); |
RoxenModule reload_module( string modname ); |
RoxenModule enable_module( string modname, RoxenModule|void me, |
ModuleInfo|void moduleinfo, |
int|void nostart, |
int|void nosave ); |
void call_start_callbacks( RoxenModule me, |
ModuleInfo moduleinfo, |
ModuleCopies module, |
void|int newly_added); |
void call_low_start_callbacks( RoxenModule me, |
ModuleInfo moduleinfo, |
ModuleCopies module ); |
int disable_module( string modname, int|void nodest ); |
int add_modules( array(string) mods, int|void now ); |
RoxenModule find_module(string name); |
#if ROXEN_COMPAT < 2.2 |
Sql.Sql sql_cache_get(string what); |
Sql.Sql sql_connect(string db, void|string charset); |
#endif |
void enable_all_modules(); |
void low_init(void|int modules_already_enabled); |
|
|
string parse_rxml(string what, RequestID id, |
void|Stdio.File file, |
void|mapping defines ); |
void add_parse_module (RoxenModule mod); |
void remove_parse_module (RoxenModule mod); |
|
string real_file(string a, RequestID b); |
|
|
mapping authenticate_throw( RequestID id, string realm, |
UserDB|void database, |
AuthModule|void method); |
User authenticate( RequestID id, |
UserDB|void database, |
AuthModule|void method ); |
|
array(AuthModule) auth_modules(); |
array(UserDB) user_databases(); |
|
AuthModule find_auth_module( string name ); |
UserDB find_user_database( string name ); |
|
protected string _sprintf( ) |
{ |
return "Configuration("+name+")"; |
} |
} |
|
|
class Protocol |
{ |
inherit BasicDefvar; |
|
constant name = "unknown"; |
|
|
constant prot_name = "unknown"; |
|
|
constant supports_ipless = 0; |
constant requesthandlerfile = ""; |
constant default_port = 4711; |
|
int bound; |
int refs; |
|
program requesthandler; |
|
string path; |
int port; |
string ip; |
array(string) sorted_urls = ({}); |
mapping(string:mapping) urls = ([]); |
mapping(Configuration:mapping) conf_data = ([]); |
|
void ref(string url, mapping data); |
void unref(string url); |
Configuration find_configuration_for_url( string url, RequestID id, |
int|void no_default ); |
string get_key(); |
void save(); |
void restore(); |
}; |
|
|
class FakedVariables( mapping real_variables ) |
{ |
|
|
protected array _indices() |
{ |
return indices( real_variables ); |
} |
|
protected array _values() |
{ |
return map( _indices(), `[] ); |
} |
|
protected mixed fix_value( mixed what ) |
{ |
if( !what ) return what; |
if( !arrayp(what) ) return what; |
|
if( sizeof( what ) == 1 ) |
return what[0]; |
return what*"\0"; |
} |
|
protected mixed `[]( string ind ) { |
return fix_value( real_variables[ ind ] ); |
} |
|
protected mixed `->(string ind ) { |
return `[]( ind ); |
} |
|
protected mixed `[]=( string ind, mixed what ) { |
real_variables[ ind ] = ({ what }); |
return what; |
} |
|
protected mixed `->=(string ind, mixed what ) { |
return `[]=( ind,what ); |
} |
|
protected mixed _m_delete( mixed what ) { |
|
return fix_value( m_delete( real_variables, what ) ); |
} |
|
protected int _equal( mixed what ) { |
return `==(what); |
} |
|
protected int `==( mixed what ) { |
if( mappingp( what ) && (real_variables == what) ) |
return 1; |
} |
|
protected string _sprintf( int f ) |
{ |
switch( f ) |
{ |
case 'O': |
return sprintf( "FakedVariables(%O)", real_variables ); |
default: |
return sprintf( sprintf("%%%c", f ), real_variables ); |
} |
} |
|
protected this_program `|( mapping what ) |
{ |
foreach( indices(what), string q )`[]=( q,what[q] ); |
return this_object(); |
} |
|
protected this_program `+=( mapping what ) |
{ |
foreach( indices(what), string q )`[]=( q,what[q] ); |
return this_object(); |
} |
|
protected this_program `+( mapping what ) |
{ |
foreach( indices(what), string q )`[]=( q,what[q] ); |
return this_object(); |
} |
|
protected mapping cast(string to) |
{ |
if (to[..6]=="mapping") |
{ |
array v=indices(real_variables); |
return mkmapping(v,map(v,`[])); |
} |
|
error("can't cast to %O\n",to); |
} |
} |
|
class PrefLanguages |
|
|
|
{ |
int decoded=0; |
int sorted=0; |
|
array(string) languages=({}); |
array(float) qualities=({}); |
|
|
|
|
|
|
|
array(array(string|array)) delayed_vary_actions = |
({ ({ "accept-language", 0 }) }); |
multiset(string) known_langs = (< >); |
|
protected string _sprintf(int c, mapping|void attrs) |
{ |
return sprintf("PrefLanguages(%O)", get_languages()); |
} |
|
void register_known_language_forks(multiset(string) langs, void|RequestID id) |
{ |
|
|
|
known_langs |= langs; |
|
|
|
if (RequestID parent_id = id && id->misc->orig) { |
PrefLanguages parent_pl = parent_id->misc->pref_languages; |
parent_pl->register_known_language_forks(langs, parent_id); |
} |
} |
|
multiset(string) get_known_language_forks() |
{ |
return known_langs; |
} |
|
void finalize_delayed_vary(RequestID id) |
{ |
|
|
if (sizeof(known_langs) < 2) |
return; |
|
VARY_WERROR("finalize_delayed_vary: actions: %O\n", delayed_vary_actions); |
foreach (delayed_vary_actions, array(string|array(string)) item) { |
function cb; |
switch (item[0]) { |
case "accept-language": |
cb = Roxen->get_lang_vary_cb(known_langs, "accept-language"); |
id->register_vary_callback("accept-language", cb); |
break; |
|
case "cookies": |
string lang_cookie = item[1]; |
cb = Roxen->get_lang_vary_cb(known_langs, "cookies", lang_cookie); |
id->register_vary_callback("cookies", cb); |
break; |
|
case "host": |
id->register_vary_callback("host"); |
break; |
|
case "variable": |
case "prestate": |
case "path": |
|
|
break; |
} |
|
|
|
|
if (array(string) property_langs = item[-1]) { |
foreach (property_langs, string lang) |
if (known_langs[lang]) |
return; |
} |
} |
} |
|
array(string) get_languages() { |
sort_lang(); |
return languages; |
} |
|
string get_language() { |
if(!languages || !sizeof(languages)) return 0; |
sort_lang(); |
return languages[0]; |
} |
|
array(float) get_qualities() { |
sort_lang(); |
return qualities; |
} |
|
float get_quality() { |
if(!qualities || !sizeof(qualities)) return 0.0; |
sort_lang(); |
return qualities[0]; |
} |
|
void set_sorted(array(string) lang, void|array(float) q) { |
languages=lang; |
if(q && sizeof(q)==sizeof(lang)) |
qualities=q; |
else |
qualities=({1.0})*sizeof(lang); |
sorted=1; |
decoded=1; |
} |
|
void sort_lang() { |
if(sorted && decoded) return; |
array(float) q; |
array(string) s=reverse(languages)-({""}) ; |
|
if(!decoded) { |
q=({}); |
s=Array.map(s, lambda(string x) { |
float n=1.0; |
string sub=""; |
sscanf(lower_case(x), "%s;q=%f", x, n); |
if(n==0.0) return ""; |
sscanf(x, "%s-%s", x, sub); |
if(x == "" ) return ""; |
q+=({n}); |
|
return x; |
}); |
s-=({""}); |
decoded=1; |
} |
else |
q=reverse(qualities); |
|
sort(q, s ); |
languages=reverse(s); |
qualities=reverse(q); |
|
|
|
multiset(string) known_langs = (< >); |
for (int i = 0; i < sizeof(languages); i++) { |
string l = languages[i]; |
if (known_langs[l]) { |
languages[i] = 0; |
qualities[i] = 0; |
} else { |
known_langs[l] = 1; |
} |
} |
languages -= ({ 0 }); |
qualities -= ({ 0 }); |
|
sorted=1; |
} |
} |
|
|
typedef function(CacheKey,mixed...:void) CacheActivationCB; |
|
class CacheKey |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
#ifdef ID_CACHEKEY_DEBUG |
RoxenDebug.ObjectMarker __marker = RoxenDebug.ObjectMarker (this); |
#endif |
|
protected array(array(CacheActivationCB|array)) activation_cbs; |
|
|
|
|
protected void create (void|int activate_immediately) |
{ |
if (!activate_immediately) activation_cbs = ({}); |
} |
|
void add_activation_cb (CacheActivationCB cb, mixed... args) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
if (activation_cbs) |
|
activation_cbs += ({({cb, args})}); |
else |
cb (this, @args); |
} |
|
int activate() |
|
|
{ |
|
if (array(array(CacheActivationCB|array)) cbs = activation_cbs) { |
|
activation_cbs = 0; |
foreach (cbs, [CacheActivationCB cb, array args]) { |
#if 0 |
werror ("Activating key %O: Calling %O(%{%O, %})\n", this, cb, args); |
#endif |
cb (this, @args); |
} |
return sizeof (cbs); |
} |
return 0; |
} |
|
int activated() |
|
{ |
|
return !activation_cbs; |
} |
|
int activate_if_necessary() |
|
|
|
|
|
|
{ |
|
if (array(array(CacheActivationCB|array)) cbs = activation_cbs) { |
if (sizeof (cbs)) { |
if (this) |
|
activation_cbs = 0; |
foreach (cbs, [CacheActivationCB cb, array args]) { |
#if 0 |
werror ("Activating key %O: Calling %O(%{%O, %})\n", this, cb, args); |
#endif |
cb (this, @args); |
} |
return 1; |
} |
} |
return 0; |
} |
|
protected string _sprintf (int flag) |
{ |
return flag == 'O' && |
sprintf ("%s(%s)%s", |
function_name (object_program (this)) || "CacheKey", |
activation_cbs ? "inactive" : "active", |
#ifdef ID_CACHEKEY_DEBUG |
__marker ? "[" + __marker->count + "]" : "", |
#else |
"" |
#endif |
); |
} |
} |
|
class TristateCacheKey |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
inherit CacheKey; |
|
protected int flags; |
|
int invalidp() |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
return flags; |
} |
|
void invalidate() |
|
|
|
|
|
|
|
|
{ |
|
flags = 1; |
} |
} |
|
class ProtocolCacheKey |
|
|
|
{ |
inherit TristateCacheKey; |
} |
|
|
protected function _charset_decoder_func; |
|
string browser_supports_vary(string ignored, RequestID id) |
{ |
return (string)!has_value(id->client||"", "MSIE"); |
} |
|
|
|
|
protected Regexp ct_charset_search = Regexp (";[ \t\n\r]*charset="); |
|
class RequestID |
|
|
|
|
|
|
|
|
{ |
#ifdef ID_OBJ_DEBUG |
RoxenDebug.ObjectMarker __marker = RoxenDebug.ObjectMarker (this); |
#endif |
|
Configuration conf; |
|
Protocol port_obj; |
|
|
int time; |
|
|
int hrtime; |
|
|
string raw_url; |
|
|
|
|
|
|
|
|
int do_not_disconnect; |
|
|
|
mapping (string:array) real_variables; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:mixed)|FakedVariables variables; |
|
|
|
|
|
|
|
|
|
mapping misc; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping connection_misc = ([]); |
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:string) real_cookies; |
|
|
|
|
|
|
|
|
|
|
|
protected class CookieJar |
{ |
|
protected mapping(string:string) eaten = ([]); |
|
protected void create(string|array(string)|void contents) |
{ |
VARY_WERROR("Initiating cookie jar.\n"); |
real_cookies = ([]); |
|
if(!contents) |
return; |
|
array tmp = arrayp(contents) ? contents : ({ contents}); |
|
foreach(tmp, string cookieheader) { |
|
foreach(((cookieheader/";") - ({""})), string c) |
{ |
string name, value; |
while(sizeof(c) && c[0]==' ') c=c[1..]; |
if(sscanf(c, "%s=%s", name, value) == 2) |
{ |
value=_Roxen.http_decode_string(value); |
name=_Roxen.http_decode_string(name); |
real_cookies[ name ]=value; |
#ifdef OLD_RXML_CONFIG |
|
if( (name == "RoxenConfig") && strlen(value) ) |
config = mkmultiset( value/"," ); |
#endif |
} |
} |
} |
} |
protected string `->(string cookie) |
{ |
if (supports && zero_type(eaten[cookie])) { |
VARY_WERROR("Looking at cookie %O from %s\n", |
cookie, describe_backtrace(({backtrace()[-2]}))); |
|
|
|
register_vary_callback("user-agent", browser_supports_vary); |
if (supports->vary) { |
register_vary_callback("cookie", Roxen->get_cookie_callback(cookie)); |
} else { |
register_vary_callback("user-agent", |
Roxen->get_cookie_callback(cookie)); |
} |
} |
return real_cookies[cookie]; |
} |
protected string `[](mixed cookie) |
{ |
if (stringp(cookie)) { |
return `->(cookie); |
} |
return UNDEFINED; |
} |
protected string `->=(string cookie, string value) |
{ |
if (zero_type(eaten[cookie])) { |
eaten[cookie] = real_cookies[cookie]; |
} |
return real_cookies[cookie] = value; |
} |
protected string `[]=(mixed cookie, string value) |
{ |
|
return `->=(cookie, value); |
} |
protected string _m_delete(string cookie) |
{ |
|
if (zero_type(eaten[cookie])) { |
eaten[cookie] = real_cookies[cookie]; |
} |
return m_delete(real_cookies, cookie); |
} |
protected array(string) _indices() |
{ |
register_vary_callback("cookie"); |
return indices(real_cookies); |
} |
protected array(string) _values() |
{ |
register_vary_callback("cookie"); |
return values(real_cookies); |
} |
protected int _sizeof() |
{ |
register_vary_callback("cookie"); |
return sizeof(real_cookies); |
} |
protected mapping(string:string) `+(mapping(string:string) other) |
{ |
register_vary_callback("cookie"); |
return real_cookies + other; |
} |
protected mapping(string:string) ``+(mapping(string:string) other) |
{ |
register_vary_callback("cookie"); |
return other + real_cookies; |
} |
|
|
|
protected mapping(string:string) `~() |
{ |
VARY_WERROR("Disconnecting cookie jar.\n"); |
return real_cookies + eaten; |
} |
|
protected string _sprintf(int fmt) |
{ |
return fmt == 'O' && sprintf("CookieJar(%O)", real_cookies); |
} |
} |
|
CookieJar|mapping(string:string) cookies; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void init_cookies(int|void no_cookie_jar) |
{ |
if (!cookies) { |
cookies = CookieJar(request_headers["cookie"]); |
if (no_cookie_jar) { |
|
real_cookies = cookies = ~cookies; |
} |
} |
} |
|
void init_pref_languages() |
|
|
|
|
|
{ |
if (!misc->pref_languages) { |
misc->pref_languages=PrefLanguages(); |
if (string|array(string) contents = request_headers[ "accept-language" ]) |
{ |
if( !arrayp( contents ) ) |
contents = (contents-" ")/","; |
else |
contents = |
Array.flatten( map( map( contents, `-, " " ), `/, "," ))-({""}); |
misc->pref_languages->languages=contents; |
misc["accept-language"] = contents; |
} |
} |
} |
|
mapping (string:array(string)|string) request_headers; |
|
|
|
|
|
|
mapping (string:mixed) throttle; |
|
|
mapping (string:mixed) client_var; |
|
|
|
multiset(string) prestate; |
|
|
|
|
|
|
|
|
|
|
|
|
|
multiset(string) config; |
|
|
|
|
|
|
|
|
multiset(string) supports; |
|
|
multiset(string) pragma; |
|
|
|
|
|
array(string) client; |
array(string) referer; |
|
Stdio.File my_fd; |
|
|
string prot; |
|
|
|
string clientprot; |
|
|
|
|
string method; |
|
|
string realfile; |
|
|
|
string virtfile; |
|
|
|
|
|
string rest_query; |
|
|
|
|
|
|
|
|
string raw; |
|
|
|
|
|
string query; |
|
|
|
|
|
|
string not_query; |
|
|
|
|
|
|
|
|
|
|
|
|
|
string input_charset; |
|
|
|
|
|
|
|
|
|
|
string extra_extension; |
|
string data; |
|
|
string leftovers; |
string rawauth, realauth; |
string since; |
|
string remoteaddr; |
|
|
string host; |
|
|
multiset(string) cache_status = (<>); |
|
|
|
|
|
|
multiset(string) eval_status = (<>); |
|
|
|
|
object root_id; |
|
|
|
|
|
protected void create(Stdio.File fd, Protocol port, Configuration conf){} |
void send(string|object what, int|void len){} |
|
protected SimpleNode xml_data; |
|
SimpleNode get_xml_data() |
{ |
if (!sizeof(data)) return 0; |
if (xml_data) return xml_data; |
|
|
DAV_WERROR("Parsing XML data: %O\n", data); |
return xml_data = |
Parser.XML.Tree.simple_parse_input(data, |
0, |
Parser.XML.Tree.PARSE_ENABLE_NAMESPACES); |
} |
|
|
protected mapping(string:array(array(array(string)))) if_data; |
|
#ifdef IF_HEADER_DEBUG |
#define IF_HDR_MSG(X...) werror (X) |
#else |
#define IF_HDR_MSG(X...) |
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:array(array(array(string)))) get_if_data() |
{ |
if (if_data) { |
IF_HDR_MSG ("get_if_data(): Returning cached result\n"); |
return sizeof(if_data) && if_data; |
} |
|
if_data = ([]); |
|
string raw_header; |
if (!(raw_header = request_headers->if)) { |
IF_HDR_MSG ("get_if_data(): No if header\n"); |
return 0; |
} |
|
array(array(string|int|array(array(string)))) decoded_if = |
MIME.decode_words_tokenized_labled(raw_header); |
|
#if 0 |
IF_HDR_MSG("get_if_data(): decoded_if: %O\n", decoded_if); |
#endif |
|
if (!sizeof(decoded_if)) { |
IF_HDR_MSG("Got only whitespace.\n"); |
return 0; |
} |
|
mapping(string:array(array(array(string)))) res = ([ 0: ({}) ]); |
|
string tmp_resource; |
string resource; |
foreach(decoded_if, array(string|int|array(array(string))) symbol) { |
switch (symbol[0]) { |
case "special": |
switch(symbol[1]) { |
case '<': tmp_resource = ""; break; |
case '>': |
resource = tmp_resource; |
tmp_resource = 0; |
|
|
|
|
catch { resource = Standards.URI(resource)->path; }; |
if (!sizeof(resource) || (resource[-1] != '/')) resource += "/"; |
if (!res[resource]) |
res[resource] = ({}); |
break; |
default: |
if (tmp_resource) tmp_resource += sprintf("%c", symbol[1]); |
break; |
} |
break; |
case "word": |
case "domain-literal": |
|
if (!tmp_resource) return 0; |
tmp_resource += symbol[1]; |
break; |
case "comment": |
|
if (tmp_resource) { |
|
tmp_resource += "(" + symbol[1][0][0] + ")"; |
break; |
} |
array(array(string|int|array(array(string)))) sub_expr = |
MIME.decode_words_tokenized_labled(symbol[1][0][0]); |
int i; |
array(array(string)) expr = ({}); |
string tmp_key; |
for (i = 0; i < sizeof(sub_expr); i++) { |
switch(sub_expr[i][0]) { |
case "special": |
switch(sub_expr[i][1]) { |
case '<': tmp_key = ""; break; |
case '>': |
if (!tmp_key) { |
IF_HDR_MSG("No tmp_key.\n"); |
return 0; |
} |
expr += ({ ({ "key", tmp_key }) }); |
tmp_key = 0; |
break; |
default: |
if (tmp_key) tmp_key += sprintf("%c", sub_expr[i][1]); |
break; |
} |
break; |
case "domain-literal": |
if (tmp_key) { |
tmp_key += sub_expr[i][1]; |
break; |
} |
|
string etag = sub_expr[i][1]; |
|
sscanf(etag, "[%s]", etag); |
expr += ({ ({ "etag", etag }) }); |
break; |
case "word": |
|
if (tmp_key) { |
tmp_key += sub_expr[i][1]; |
break; |
} |
if (lower_case(sub_expr[i][1]) == "not") { |
|
expr += ({ ({ "not", 0 }) }); |
break; |
} |
IF_HDR_MSG("Word outside key: %O\n", sub_expr[i][1]); |
report_debug("Syntax error in if-header: %O\n", raw_header); |
return 0; |
} |
} |
if (tmp_key) { |
IF_HDR_MSG("Active tmp_key: %O\n", tmp_key); |
report_debug("Syntax error in if-header: %O\n", raw_header); |
return 0; |
} |
res[resource] += ({ expr }); |
break; |
default: |
report_debug("Syntax error in if-header: %O\n", raw_header); |
return 0; |
} |
} |
if (tmp_resource) { |
IF_HDR_MSG("Active tmp_resource: %O\n", tmp_resource); |
report_debug("Syntax error in if-header: %O\n", raw_header); |
return 0; |
} |
IF_HDR_MSG("get_if_data(): Parsed if header: %s:\n" |
"%O\n", raw_header, res); |
return if_data = res; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void register_vary_callback(string|void vary, |
function(string, RequestID: string|int)|void cb) |
{ |
|
if (vary != "host") { |
if (!misc->vary) { |
misc->vary = (< vary || "*" >); |
} else { |
misc->vary[vary || "*"] = 1; |
} |
} |
if (!misc->vary_cb_set) { |
misc->vary_cb_set = cb ? ([vary: (<cb>)]) : ([vary: 1]); |
misc->vary_cb_order = ({ cb || vary }); |
VARY_WERROR("register_vary_callback(%O, %O)\n", vary, cb); |
return; |
} |
if (multiset(function(string,RequestID:string|int))|int(1..1) old = |
misc->vary_cb_set[vary]) { |
if (old == 1) { |
|
VARY_WERROR("register_vary_callback(%O, %O) Full header\n", vary, cb); |
return; |
} |
else if (old[cb]) { |
|
VARY_WERROR("register_vary_callback(%O, %O) Duplicate\n", vary, cb); |
return; |
} |
else if (!cb) { |
|
misc->vary_cb_order = misc->vary_cb_order - (array) old + ({vary}); |
misc->vary_cb_set[vary] = 1; |
VARY_WERROR("register_vary_callback(%O, 0) Removed old cbs\n", vary); |
return; |
} |
old[cb] = 1; |
} |
else |
misc->vary_cb_set[vary] = cb ? (<cb>) : 1; |
misc->vary_cb_order += ({ cb || vary }); |
VARY_WERROR("register_vary_callback(%O, %O)\n", vary, cb); |
} |
|
void unregister_vary_callback (string vary, |
void|function(string,RequestID:string|int) cb) |
|
|
|
|
|
|
|
|
{ |
if (misc->vary) |
misc->vary[vary || "*"] = 0; |
if (!misc->vary_cb_set) { |
VARY_WERROR ("unregister_vary_callback (%O, %O) " |
"Got no vary registrations\n", vary, cb); |
return; |
} |
if (multiset(function(string,RequestID:string|int))|int(1..1) old = |
misc->vary_cb_set[vary]) { |
if (multisetp (old)) { |
if (cb) { |
if (old[cb]) { |
misc->vary_cb_order -= ({cb}); |
old[cb] = 0; |
if (!sizeof (old)) m_delete (misc->vary_cb_set, vary); |
VARY_WERROR ("unregister_vary_callback (%O, %O) " |
"Removed callback\n", vary, cb); |
} |
else { |
VARY_WERROR ("unregister_vary_callback (%O, %O) " |
"Callback wasn't registered\n", vary, cb); |
} |
} |
else { |
misc->vary_cb_order -= (array) old; |
m_delete (misc->vary_cb_set, vary); |
VARY_WERROR ("unregister_vary_callback (%O, 0) " |
"Removed %d callbacks\n", vary, sizeof (old)); |
} |
} |
else { |
if (cb) { |
VARY_WERROR ("unregister_vary_callback (%O, %O) " |
"Callback wasn't registered\n", vary, cb); |
} |
else { |
misc->vary_cb_order -= ({vary}); |
m_delete (misc->vary_cb_set, vary); |
VARY_WERROR ("unregister_vary_callback (%O, 0) " |
"Removed header\n", vary); |
} |
} |
} |
} |
|
protected string cached_url_base; |
|
string url_base() |
|
|
|
|
|
|
|
{ |
if (!cached_url_base) { |
string tmp; |
|
|
register_vary_callback("host"); |
|
|
if (tmp = misc->host) { |
string scheme = port_obj->prot_name; |
if (has_prefix(tmp, "[")) { |
|
sscanf(tmp, "[%s]:%d", string host, int port); |
if (!port || port == port_obj->default_port) |
cached_url_base = scheme + "://[" + host + "]"; |
else |
cached_url_base = scheme + "://" + tmp; |
} else { |
int scanres = sscanf(tmp, "%[^:]:%d", string host, int port); |
if ((scanres < 2) || (port == port_obj->default_port)) { |
|
|
|
|
|
|
cached_url_base = scheme + "://" + host; |
} else { |
cached_url_base = scheme + "://" + tmp; |
} |
} |
} |
|
|
else if (port_obj) { |
string host = port_obj->conf_data[conf]->hostname; |
if (host == "*") |
if (conf && sizeof (host = conf->get_url()) && |
(sscanf (host, "%*s://[%s]", string hostv6) == 2 || |
sscanf (host, "%*s://%[^:/]", string hostv4) == 2)) { |
|
host = hostv6 ? ("[" + hostv6 + "]") : hostv4; |
} |
else |
|
host = port_obj->ip; |
cached_url_base = port_obj->prot_name + "://" + host; |
if (port_obj->port != port_obj->default_port) |
cached_url_base += ":" + port_obj->port; |
} |
|
|
else if (conf && sizeof (tmp = conf->get_url())) |
cached_url_base = tmp[..sizeof (tmp) - 2]; |
|
|
|
else return cached_url_base = ""; |
|
if (string p = misc->site_prefix_path) cached_url_base += p; |
cached_url_base += "/"; |
} |
return cached_url_base; |
} |
|
void add_response_header (string name, string value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
mapping(string:string|array(string)) hdrs = |
misc->defines && misc->defines[" _extra_heads"] || misc->moreheads; |
if (!hdrs) hdrs = misc->moreheads = ([]); |
|
|
|
array|string cur_val = hdrs[name]; |
if(cur_val) { |
if(arrayp(cur_val)) { |
if (!has_value(cur_val, value)) |
cur_val += ({ value }); |
} else { |
if (cur_val != value) |
cur_val = ({ cur_val, value }); |
} |
} |
else |
cur_val = value; |
|
if (hdrs == misc->moreheads) |
hdrs[name] = cur_val; |
else if (object ctx = RXML_CONTEXT) |
ctx->set_var (name, cur_val, "header"); |
else |
hdrs[name] = cur_val; |
} |
|
void set_response_header (string name, string value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
if (misc->defines && misc->defines[" _extra_heads"]) { |
misc->defines[" _extra_heads"][name] = value; |
if (object ctx = RXML_CONTEXT) |
ctx->signal_var_change (name, "header"); |
} |
else { |
if (!misc->moreheads) misc->moreheads = ([]); |
misc->moreheads[name] = value; |
} |
} |
|
protected constant http_nontoken_chars = ([ |
0:1, 1:1, 2:1, 3:1, 4:1, 5:1, 6:1, 7:1, 8:1, 9:1, 10:1, 11:1, 12:1, 13:1, |
14:1, 15:1, 16:1, 17:1, 18:1, 19:1, 20:1, 21:1, 22:1, 23:1, 24:1, 25:1, |
26:1, 27:1, 28:1, 29:1, 30:1, 31:1, '(':1, ')':1, '<':1, '>':1, '@':1, |
',':1, ';':1, ':':1, '\\':1, '"':1, '/':1, '[':1, ']':1, '?':1, '=':1, |
'{':1, '}':1, ' ':1, '\t':1]); |
|
#define MATCH_TOKEN_PREFIX(VAL, PREFIX) \ |
(VAL == PREFIX || \ |
has_prefix (VAL, PREFIX) && http_nontoken_chars[VAL[sizeof (PREFIX)]]) |
|
array(string) get_response_headers (string name, void|string value_prefix) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
array(string) res = ({}); |
|
foreach (({misc->defines && misc->defines[" _extra_heads"], |
misc->moreheads}), |
mapping(string:string|array(string)) hdrs) |
if (hdrs) { |
if (array(string)|string cur_val = hdrs[name]) { |
if (!value_prefix) |
res += arrayp (cur_val) ? cur_val : ({cur_val}); |
else { |
if (arrayp (cur_val)) { |
foreach (cur_val, string val) |
if (MATCH_TOKEN_PREFIX (val, value_prefix)) |
res += ({val}); |
} |
else |
if (MATCH_TOKEN_PREFIX (cur_val, value_prefix)) |
res += ({cur_val}); |
} |
} |
} |
|
return res; |
} |
|
int remove_response_headers (string name, void|string value_prefix) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
int removed; |
|
foreach (({misc->defines && misc->defines[" _extra_heads"], |
misc->moreheads}), |
mapping(string:string|array(string)) hdrs) |
if (hdrs) { |
if (array(string)|string cur_val = hdrs[name]) { |
if (!value_prefix) { |
m_delete (hdrs, name); |
removed = 1; |
} |
else { |
if (arrayp (cur_val)) { |
foreach (cur_val; int i; string val) |
if (MATCH_TOKEN_PREFIX (val, value_prefix)) { |
cur_val[i] = 0; |
removed = 1; |
} |
cur_val -= ({0}); |
if (sizeof (cur_val)) hdrs[name] = cur_val; |
else m_delete (hdrs, name); |
} |
else |
if (MATCH_TOKEN_PREFIX (cur_val, value_prefix)) { |
m_delete (hdrs, name); |
removed = 1; |
} |
} |
} |
} |
|
return removed; |
} |
|
protected MultiStatus multi_status; |
|
MultiStatus get_multi_status() |
|
|
|
|
|
|
|
|
|
|
|
|
{ |
if (!multi_status) multi_status = MultiStatus(); |
return multi_status; |
} |
|
int multi_status_size() |
|
|
|
|
{ |
return multi_status && multi_status->num_responses(); |
} |
|
void set_status_for_path (string path, int status_code, |
string|void message, mixed... args) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
if (sizeof (args)) message = sprintf (message, @args); |
ASSERT_IF_DEBUG (has_prefix (path, "/")); |
get_multi_status()->add_status (url_base() + path[1..], |
status_code, message); |
} |
|
void set_status_for_url (string url, int status_code, |
string|void message, mixed... args) |
|
|
|
|
{ |
if (sizeof (args)) message = sprintf (message, @args); |
get_multi_status()->add_status (url, status_code, message); |
} |
|
|
|
|
array(string) output_charset = ({}); |
|
void set_output_charset( string|function to, int|void mode ) |
{ |
#ifdef DEBUG |
if (stringp (to)) |
|
Locale.Charset.encoder (to); |
#endif |
|
if (object ctx = RXML_CONTEXT) |
ctx->add_p_code_callback ("set_output_charset", to, mode); |
|
if( has_value (output_charset, to) ) |
return; |
|
switch( mode ) |
{ |
case 0: |
output_charset = ({ to }); |
break; |
|
case 1: |
if( !sizeof( output_charset ) ) |
output_charset = ({ to }); |
break; |
|
case 2: |
if (sizeof (output_charset) && |
(!stringp (to) || !stringp (output_charset[0]))) |
error ("Can't join charsets with functions (%O with %O).\n", |
to, output_charset[0]); |
output_charset += ({ to }); |
break; |
} |
} |
|
string|function(string:string) get_output_charset() |
{ |
string charset; |
function(string:string) encoder; |
foreach( output_charset, string|function f ) |
[charset,encoder] = join_charset(charset, f, encoder, 0); |
return charset || encoder; |
} |
|
protected string charset_name(function|string what) |
{ |
switch (what) { |
case string_to_unicode: return "ISO10646-1"; |
case string_to_utf8: return "UTF-8"; |
default: return upper_case((string) what); |
} |
} |
|
protected function charset_function(function|string what, int allow_entities) |
{ |
switch (what) { |
case "ISO-10646-1": |
case "ISO10646-1": |
case string_to_unicode: |
return string_to_unicode; |
|
case "UTF-8": |
case string_to_utf8: |
return string_to_utf8; |
|
default: |
|
function fallback_func = |
allow_entities && |
lambda(string char) { |
return sprintf("&#x%x;", char[0]); |
}; |
|
_charset_decoder_func = |
_charset_decoder_func || Roxen->_charset_decoder; |
return |
_charset_decoder_func(Locale.Charset.encoder((string) what, "", |
fallback_func)) |
->decode; |
} |
} |
|
protected array(string) join_charset(string old, |
function|string add, |
function oldcodec, |
int allow_entities) |
{ |
switch (old && upper_case(old)) { |
case 0: |
case "ISO8859-1": |
case "ISO-8859-1": |
return ({ charset_name(add), charset_function(add, allow_entities) }); |
case "ISO10646-1": |
case "UTF-8": |
return ({ old, oldcodec }); |
case "ISO-2022": |
return ({ old, oldcodec }); |
default: |
|
#if 1 |
|
return ({"UTF-8", string_to_utf8}); |
#else |
return ({ charset_name(add), charset_function(add, allow_entities) }); |
#endif |
} |
} |
|
array replace_charset_placeholder(string charset, string what, int allow_entities) { |
|
if(allow_entities && charset) |
what = replace(what, Roxen->magic_charset_variable_placeholder, charset); |
return ({ charset, what }); |
} |
|
array(string) output_encode(string what, int|void allow_entities, |
string|void force_charset) |
{ |
|
|
if (String.width(what) == 8) { |
if (force_charset) { |
if (upper_case(force_charset) == "ISO-8859-1") |
return replace_charset_placeholder("ISO-8859-1", what, allow_entities); |
} else { |
if (sizeof(output_charset) == 1 && |
upper_case(output_charset[0]) == "ISO-8859-1") |
return replace_charset_placeholder("ISO-8859-1", what, allow_entities); |
} |
} |
|
if (!force_charset) { |
string charset; |
function encoder; |
|
foreach( output_charset, string|function f ) |
[charset,encoder] = join_charset(charset, f, encoder, allow_entities); |
if (!encoder) |
if (String.width(what) > 8) { |
charset = "UTF-8"; |
encoder = string_to_utf8; |
} |
if (encoder) |
what = encoder(what); |
return replace_charset_placeholder( charset, what, allow_entities ); |
} else |
return ({ |
0, |
Locale.Charset.encoder((force_charset / "=")[-1])->feed(what)->drain() |
}); |
} |
|
string decode_query (string path, array(string) split_query, |
string decode_charset) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
path = _Roxen.http_decode_string (path); |
|
mapping(string:array(string)) vars = ([]); |
string rest; |
{ |
array(string) rests = ({}); |
foreach (split_query, string v) { |
if(sscanf(v, "%s=%s", string a, string b) == 2) |
{ |
a = _Roxen.http_decode_string(replace(a, "+", " ")); |
b = _Roxen.http_decode_string(replace(b, "+", " ")); |
vars[ a ] += ({ b }); |
} else |
rests += ({_Roxen.http_decode_string( v )}); |
} |
rest = rests * "&"; |
} |
|
#ifdef ENABLE_IDIOTIC_STUPID_STANDARD |
|
|
|
|
rest=replace(rest, "+", "\000"); |
#endif |
|
do_decode_charset: |
if (decode_charset == "roxen-http-default") { |
array(string) magic = vars->magic_roxen_automatic_charset_variable; |
decode_charset = magic && Roxen->get_client_charset (magic[0]); |
function(string:string) decoder = decode_charset ? |
Roxen->get_decoder_for_client_charset (decode_charset) : |
utf8_to_string; |
|
mapping(string:array(string)) decoded_vars = ([]); |
if (mixed err = catch { |
path = decoder (path); |
foreach (vars; string var; array(string) vals) |
decoded_vars[var] = map (vals, decoder); |
rest = decoder (rest); |
}) { |
#ifdef DEBUG |
if (decode_charset) |
report_debug ("Failed to decode query %O using charset %O derived " |
"from magic_roxen_automatic_charset_variable %O: %s", |
({path, (split_query + ({rest})) * "&"}) * "?", |
decode_charset, magic[0], describe_error (err)); |
#if 0 |
else |
report_debug ("Failed to decode query %O using UTF-8: %s", |
({path, (split_query + ({rest})) * "&"}) * "?", |
describe_error (err)); |
#endif |
#endif |
} |
else { |
vars = decoded_vars; |
input_charset = decode_charset || "utf-8"; |
} |
} |
|
else if (decode_charset) { |
if (decode_charset == "magic") { |
array(string) magic = vars->magic_roxen_automatic_charset_variable; |
decode_charset = magic && Roxen->get_client_charset (magic[0]); |
if (!decode_charset) |
break do_decode_charset; |
} |
|
function(string:string) decoder = |
Roxen->get_decoder_for_client_charset (decode_charset); |
path = decoder (path); |
foreach (vars; string var; array(string) vals) |
vars[var] = map (vals, decoder); |
rest = decoder (rest); |
input_charset = decode_charset; |
} |
|
if (sizeof (real_variables)) |
foreach (vars; string var; array(string) vals) |
real_variables[var] += vals; |
else { |
real_variables = vars; |
|
variables = FakedVariables (vars); |
} |
|
rest_query = rest; |
|
return path; |
} |
|
string scan_for_query( string f ) |
{ |
if(sscanf(f,"%s?%s", f, query) == 2) |
f = decode_query (f, query / "&", 0); |
return f; |
} |
|
mapping(string:string|array(string)) make_response_headers ( |
mapping(string:mixed) file) |
|
|
|
|
|
|
|
|
{ |
if (!file->stat) file->stat = misc->stat; |
if(objectp(file->file)) { |
if(!file->stat && file->file->stat) |
file->stat = file->file->stat(); |
if (zero_type(misc->cacheable) && file->file->is_file) { |
|
misc->cacheable = (predef::time(1) - file->stat[ST_MTIME])/4; |
} |
} |
|
if( Stat fstat = file->stat ) |
{ |
if( !file->len && (fstat[1] >= 0) && file->file ) |
file->len = fstat[1]; |
if ( fstat[ST_MTIME] > misc->last_modified ) |
misc->last_modified = fstat[ST_MTIME]; |
} |
|
if (!file->error) |
file->error = Protocols.HTTP.HTTP_OK; |
|
if(!file->type) file->type="text/plain"; |
string type = arrayp(file->type) ? file->type[0] : file->type; |
|
mapping(string:string) heads = ([]); |
|
|
|
if (PrefLanguages pl = misc->pref_languages) |
pl->finalize_delayed_vary(this); |
|
if( !zero_type(misc->cacheable) && |
(misc->cacheable != INITIAL_CACHEABLE) ) { |
if (!misc->cacheable) { |
|
heads["Expires"] = Roxen->http_date( predef::time(1)-31557600 ); |
|
misc->vary = (< 0 >); |
VARY_WERROR("Not cacheable. Force vary *.\n"); |
} else |
heads["Expires"] = Roxen->http_date( predef::time(1)+misc->cacheable ); |
if (misc->cacheable < INITIAL_CACHEABLE) { |
|
|
misc->last_modified = predef::time(1); |
} |
} |
|
if (misc->last_modified) |
heads["Last-Modified"] = Roxen->http_date(misc->last_modified); |
|
if (has_prefix (type, "text/") && !ct_charset_search->match (type)) { |
string charset; |
|
if( stringp(file->data) ) { |
if (file->charset) |
|
set_output_charset (file->charset, 2); |
|
if (sizeof (output_charset) || (String.width(file->data) > 8)) |
{ |
int allow_entities = |
has_prefix(type, "text/xml") || |
has_prefix(type, "text/html"); |
[charset, file->data] = output_encode( file->data, allow_entities ); |
} |
} |
|
|
|
|
type += "; charset=" + (charset || "ISO-8859-1"); |
} |
|
heads["Content-Type"] = type; |
|
if (stringp (file->data)) |
file->len = sizeof (file->data); |
|
#ifndef DISABLE_BYTE_RANGES |
heads["Accept-Ranges"] = "bytes"; |
#endif |
heads["Server"] = replace(roxenp()->version(), " ", "_"); |
if (file->error == 500) { |
|
|
heads["Connection"] = "close"; |
misc->connection = "close"; |
} else if( misc->connection ) |
heads["Connection"] = misc->connection; |
|
if(file->encoding) heads["Content-Encoding"] = file->encoding; |
|
heads->Date = Roxen->http_date(predef::time(1)); |
if(file->expires) |
heads->Expires = Roxen->http_date(file->expires); |
|
|
heads["Content-Length"] = (string)file->len; |
|
if (misc->etag) |
heads->ETag = misc->etag; |
|
#ifdef RAM_CACHE |
if (!misc->etag && file->len && |
(file->data || file->file) && |
file->error == 200 && (<"HEAD", "GET">)[method] && |
(file->len < conf->datacache->max_file_size)) { |
string data = ""; |
if (file->file) { |
data = file->file->read(file->len); |
if (file->data && (sizeof(data) < file->len)) { |
data += file->data[..file->len - (sizeof(data)+1)]; |
} |
m_delete(file, "file"); |
} else if (file->data) { |
data = file->data[..file->len - 1]; |
} |
file->data = data; |
heads->ETag = misc->etag = |
sprintf("\"%s\"", String.string2hex(Crypto.MD5.hash(data))); |
} |
#endif /* RAM_CACHE */ |
|
if (misc->vary && sizeof(misc->vary)) { |
|
VARY_WERROR("Full set: %s\n", ((array)misc->vary) * ", "); |
if (!supports->vary) { |
|
heads->Vary = "User-Agent"; |
#ifndef DISABLE_VARY_EXPIRES_FALLBACK |
|
heads->Expires = Roxen->http_date(predef::time(1)-31557600); |
#endif /* !DISABLE_VARY_EXPIRES_FALLBACK */ |
VARY_WERROR("Vary not supported by the browser.\n"); |
} else if (misc->vary[0]) { |
|
heads->Vary = "*"; |
} else { |
heads->Vary = ((array)misc->vary) * ", "; |
} |
} |
|
|
|
|
|
|
if(mappingp(file->extra_heads)) |
heads |= file->extra_heads; |
|
if(mappingp(misc->moreheads)) |
heads |= misc->moreheads; |
|
return heads; |
} |
|
void adjust_for_config_path( string p ) |
{ |
if( not_query ) not_query = not_query[ strlen(p).. ]; |
raw_url = raw_url[ strlen(p).. ]; |
misc->site_prefix_path = p; |
} |
|
void end(string|void s, int|void keepit){} |
void ready_to_receive(){} |
|
void send_result(mapping|void result) |
{ |
#ifdef DEBUG |
error ("send_result not overridden.\n"); |
#endif |
} |
|
RequestID clone_me() |
{ |
object c,t; |
c=object_program(t=this_object())(0, port_obj, conf); |
|
c->port_obj = port_obj; |
c->conf = conf; |
c->root_id = root_id; |
c->time = time; |
c->raw_url = raw_url; |
|
c->real_variables = copy_value( real_variables ); |
c->variables = FakedVariables( c->real_variables ); |
c->misc = copy_value( misc ); |
c->misc->orig = t; |
|
c->connection_misc = connection_misc; |
|
c->prestate = prestate; |
c->supports = supports; |
c->config = config; |
c->client_var = client_var; |
|
c->remoteaddr = remoteaddr; |
c->host = host; |
|
c->client = client; |
c->referer = referer; |
c->pragma = pragma; |
|
c->cookies = cookies; |
c->request_headers = request_headers + ([]); |
c->my_fd = 0; |
c->prot = prot; |
c->clientprot = clientprot; |
c->method = method; |
|
c->rest_query = rest_query; |
c->raw = raw; |
c->query = query; |
c->not_query = not_query; |
c->data = data; |
c->extra_extension = extra_extension; |
|
c->realauth = realauth; |
c->rawauth = rawauth; |
c->since = since; |
return c; |
} |
|
Stdio.File connection( ) |
|
{ |
return my_fd; |
} |
|
Configuration configuration() |
|
|
{ |
return conf; |
} |
|
string _sprintf (int flag) |
{ |
return flag == 'O' && ("RequestID(" + (raw_url||"") + ")" |
#ifdef ID_OBJ_DEBUG |
+ (__marker ? "[" + __marker->count + "]" : "") |
#endif |
); |
} |
} |
|
|
class MultiStatusStatus (int http_code, void|string message) |
{ |
constant is_status = 1; |
|
void build_response (SimpleElementNode response_node) |
{ |
SimpleElementNode node = SimpleElementNode("DAV:status", ([])); |
response_node->add_child (node); |
|
|
node->add_child(SimpleTextNode(sprintf("HTTP/1.1 %d ", http_code))); |
|
if (message) { |
node = SimpleElementNode ("DAV:responsedescription", ([])); |
response_node->add_child (node); |
node->add_child (SimpleTextNode (message)); |
} |
} |
|
int `== (mixed other) |
{ |
return objectp (other) && |
object_program (other) == this_program && |
other->http_code == http_code && |
other->message == message; |
} |
|
int __hash() |
{ |
return http_code + (message && hash (message)); |
} |
|
string _sprintf (int flag) |
{ |
return flag == 'O' && |
sprintf ("MultiStatusStatus(%d,%O)", http_code, message); |
} |
} |
|
private SimpleElementNode ok_status_node = |
SimpleElementNode("DAV:status", ([]))->add_child(SimpleTextNode("HTTP/1.1 200 OK")); |
|
|
class MultiStatusPropStat |
{ |
constant is_prop_stat = 1; |
|
mapping(string:string|SimpleNode|array(SimpleNode)|MultiStatusStatus) |
properties = ([]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void build_response (SimpleElementNode response_node) |
{ |
SimpleElementNode ok_prop_node = SimpleElementNode("DAV:prop", ([])); |
mapping(MultiStatusStatus:SimpleNode) prop_nodes = ([]); |
|
foreach (properties; |
string prop_name; |
string|SimpleNode|array(SimpleNode)|MultiStatusStatus value) { |
if (objectp (value) && value->is_status) { |
|
SimpleNode prop_node = prop_nodes[value]; |
if (!prop_node) |
prop_nodes[value] = prop_node = SimpleElementNode("DAV:prop", ([])); |
prop_node->add_child(SimpleElementNode(prop_name, ([]))); |
} |
|
else { |
|
|
string ms_type; |
|
|
|
switch (prop_name) { |
case "DAV:creationdate": ms_type = "dateTime.tz"; break; |
case "DAV:getlastmodified": ms_type = "dateTime.rfc1123"; break; |
|
|
} |
SimpleElementNode node = |
SimpleElementNode(prop_name, |
ms_type ? |
([ "urn:schemas-microsoft-com:datatypesdt": |
ms_type ]) : ([])); |
ok_prop_node->add_child (node); |
|
if (arrayp (value)) |
node->replace_children (value); |
else if (stringp (value)) |
node->add_child(SimpleTextNode(value)); |
else if (objectp (value)) |
node->add_child (value); |
} |
} |
|
if (ok_prop_node->count_children()) { |
SimpleElementNode propstat_node = |
SimpleElementNode("DAV:propstat", ([])); |
response_node->add_child (propstat_node); |
propstat_node->add_child (ok_prop_node); |
propstat_node->add_child (ok_status_node); |
} |
|
foreach (prop_nodes; MultiStatusStatus status; SimpleNode prop_node) { |
SimpleElementNode propstat_node = |
SimpleElementNode("DAV:propstat", ([])); |
response_node->add_child (propstat_node); |
propstat_node->add_child (prop_node); |
status->build_response (propstat_node); |
} |
} |
|
string _sprintf (int flag) |
{ |
return flag == 'O' && sprintf ("MultiStatusPropStat(%O)", properties); |
} |
} |
|
|
typedef MultiStatusStatus|MultiStatusPropStat MultiStatusNode; |
|
|
class MultiStatus |
{ |
protected mapping(string:MultiStatusNode) status_set = ([]); |
|
protected mapping(string:string) args = ([ |
"xmlns:DAV": "DAV:", |
|
|
|
|
"xmlns:MS": "urn:schemas-microsoft-com:datatypes", |
]); |
|
int num_responses() |
|
|
{ |
return sizeof (status_set); |
} |
|
MultiStatusNode get_response (string href) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
return status_set[href]; |
} |
|
mapping(string:MultiStatusNode) get_responses_by_prefix (string href_prefix) |
|
|
|
|
|
|
|
|
|
{ |
if (href_prefix == "") |
return status_set + ([]); |
mapping(string:MultiStatusNode) result = ([]); |
if (!has_suffix (href_prefix, "/")) { |
if (MultiStatusNode stat = status_set[href_prefix]) |
result[href_prefix] = stat; |
href_prefix += "/"; |
} |
foreach (status_set; string href; MultiStatusNode stat) |
if (has_prefix (href, href_prefix)) |
result[href] = stat; |
return result; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void add_property(string href, string prop_name, |
void|int(0..0)|string|array(SimpleNode)|SimpleNode| |
MultiStatusStatus|mapping(string:mixed) prop_value) |
{ |
MultiStatusPropStat prop_stat; |
if (MultiStatusNode stat = status_set[href]) |
if (stat->is_prop_stat) |
|
|
|
|
prop_stat = stat; |
if (!prop_stat) |
prop_stat = status_set[href] = MultiStatusPropStat(); |
if (mappingp (prop_value)) |
prop_value = MultiStatusStatus (prop_value->error, prop_value->rettext); |
prop_stat->properties[prop_name] = prop_value; |
} |
|
void add_status (string href, int status_code, |
void|string message, mixed... args) |
|
|
{ |
if (sizeof (args)) message = sprintf (message, @args); |
if (!status_code) error("Bad status code!\n"); |
status_set[href] = MultiStatusStatus (status_code, message); |
} |
|
void add_namespace (string namespace) |
|
|
{ |
int ns_count = 0; |
string ns_name; |
while (args[ns_name = "xmlns:NS" + ns_count]) { |
if (args[ns_name] == namespace) return; |
ns_count++; |
} |
args[ns_name] = namespace; |
} |
|
SimpleNode get_xml_node() |
{ |
SimpleElementNode node; |
SimpleRootNode root = SimpleRootNode()-> |
add_child(SimpleHeaderNode((["version": "1.0", |
"encoding": "utf-8"])))-> |
add_child(node = SimpleElementNode("DAV:multistatus", args)); |
|
array(SimpleNode) response_xml = allocate(sizeof(status_set)); |
int i; |
|
DAV_WERROR("Generating XML Nodes for status_set:%O\n", |
status_set); |
|
|
|
foreach(sort(indices(status_set)), string href) { |
SimpleElementNode response_node = |
SimpleElementNode("DAV:response", ([]))-> |
add_child(SimpleElementNode("DAV:href", ([]))-> |
add_child(SimpleTextNode(href))); |
response_xml[i++] = response_node; |
status_set[href]->build_response (response_node); |
} |
node->replace_children(response_xml); |
|
return root; |
} |
|
mapping(string:mixed) http_answer() |
{ |
string xml = get_xml_node()->render_xml(); |
return ([ |
"error": 207, |
"data": xml, |
"len": sizeof(xml), |
"type": "text/xml; charset=\"utf-8\"", |
]); |
} |
|
class Prefixed (protected string href_prefix) |
{ |
MultiStatus get_multi_status() {return MultiStatus::this;} |
void add_property(string path, string prop_name, |
void|int(0..0)|string|array(SimpleNode)|SimpleNode| |
MultiStatusStatus|mapping(string:mixed) prop_value) |
{ |
MultiStatus::add_property(href_prefix + path, prop_name, prop_value); |
} |
void add_status (string path, int status_code, |
void|string message, mixed... args) |
{ |
MultiStatus::add_status (href_prefix + path, status_code, message, @args); |
} |
void add_namespace (string namespace) |
{ |
MultiStatus::add_namespace (namespace); |
} |
MultiStatus.Prefixed prefix(string href_prefix) { |
return this_program (this_program::href_prefix + href_prefix); |
} |
} |
|
MultiStatus.Prefixed prefix (string href_prefix) |
|
|
|
{ |
return Prefixed (href_prefix); |
} |
} |
|
|
protected class PropertySet |
{ |
string path; |
RequestID id; |
Stat get_stat(); |
mapping(string:string) get_response_headers(); |
multiset(string) query_all_properties(); |
string|array(SimpleNode)|mapping(string:mixed) |
query_property(string prop_name); |
mapping(string:mixed) start(); |
void unroll(); |
void commit(); |
mapping(string:mixed) set_property(string prop_name, |
string|array(SimpleNode) value); |
mapping(string:mixed) set_dead_property(string prop_name, |
array(SimpleNode) value); |
mapping(string:mixed) remove_property(string prop_name); |
mapping(string:mixed) find_properties(string mode, |
MultiStatus.Prefixed result, |
multiset(string)|void filt); |
} |
|
|
enum LockFlag { |
LOCK_NONE = 0, |
LOCK_SHARED_BELOW = 2, |
LOCK_SHARED_AT = 3, |
LOCK_OWN_BELOW = 4, |
LOCK_EXCL_BELOW = 6, |
LOCK_EXCL_AT = 7 |
}; |
|
|
|
enum Overwrite { |
|
|
NEVER_OVERWRITE = -1, |
|
|
|
|
|
MAYBE_OVERWRITE = 0, |
|
|
|
|
DO_OVERWRITE = 1, |
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef int(0..1)|multiset(string) PropertyBehavior; |
|
class RoxenModule |
{ |
inherit BasicDefvar; |
constant is_module = 1; |
constant module_type = 0; |
constant module_unique = 1; |
LocaleString module_name; |
LocaleString module_doc; |
|
string module_identifier(); |
string module_local_id(); |
|
array(int|string|mapping) register_module(); |
string file_name_and_stuff(); |
|
void start (void|int variable_save, void|Configuration conf, |
void|int newly_added); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void stop(); |
|
|
|
|
void ready_to_receive_requests (void|Configuration conf); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string query_internal_location(); |
string query_location(); |
string|multiset(string) query_provides(); |
function(RequestID:int|mapping) query_seclevels(); |
void set_status_for_path (string path, RequestID id, int status_code, |
string|void message, mixed... args); |
array(int)|object(Stdio.Stat) stat_file(string f, RequestID id); |
array(string) find_dir(string f, RequestID id); |
mapping(string:array(mixed)) find_dir_stat(string f, RequestID id); |
string real_file(string f, RequestID id); |
void save(); |
mapping api_functions(); |
mapping query_tag_callers(); |
mapping query_container_callers(); |
|
string info(object conf); |
string comment(); |
|
PropertySet|mapping(string:mixed) query_property_set(string path, RequestID id); |
string|array(SimpleNode)|mapping(string:mixed) |
query_property(string path, string prop_name, RequestID id); |
mapping(string:mixed) recurse_find_properties(string path, string mode, int depth, |
RequestID id, |
multiset(string)|void filt); |
mapping(string:mixed) patch_properties(string path, |
array(PatchPropertyCommand) instructions, |
RequestID id); |
mapping(string:mixed) set_property (string path, string prop_name, |
string|array(SimpleNode) value, |
RequestID id); |
mapping(string:mixed) remove_property (string path, string prop_name, |
RequestID id); |
|
string resource_id (string path, RequestID id); |
string|int authenticated_user_id (string path, RequestID id); |
multiset(DAVLock) find_locks(string path, |
int(0..1) recursive, |
int(0..1) exclude_shared, |
RequestID id); |
DAVLock|LockFlag check_locks(string path, |
int(0..1) recursive, |
RequestID id); |
mapping(string:mixed) lock_file(string path, |
DAVLock lock, |
RequestID id); |
mapping(string:mixed) unlock_file (string path, |
DAVLock lock, |
RequestID id); |
mapping(string:mixed)|int(0..1) check_if_header(string relative_path, |
int(0..1) recursive, |
RequestID id); |
|
mapping(string:mixed)|int(-1..0)|Stdio.File find_file(string path, |
RequestID id); |
mapping(string:mixed) recurse_delete_files(string path, |
RequestID id); |
mapping(string:mixed) make_collection(string path, RequestID id); |
mapping(string:mixed) recurse_copy_files(string source, string destination, |
PropertyBehavior behavior, |
Overwrite overwrite, RequestID id); |
mapping(string:mixed) recurse_move_files(string source, string destination, |
PropertyBehavior behavior, |
Overwrite overwrite, RequestID id); |
} |
|
class PatchPropertyCommand |
{ |
constant command = ""; |
string property_name; |
mapping(string:mixed) execute(PropertySet context); |
} |
|
class _roxen |
{ |
mapping(string:object) variables; |
constant real_version = ""; |
object locale; |
int start_time; |
array(Configuration) configurations; |
|
mixed query(string a); |
void store(string a, mapping b, int c, object d); |
mapping(string:mixed) retrieve(string a, object b); |
void remove(string a, object b); |
string version(); |
void dump(string a); |
void nwrite(string a, int|void b, int|void c, void|mixed ... d); |
int main(int a, array(string) b); |
} |
|
class AuthModule |
|
|
{ |
inherit RoxenModule; |
constant module_type = MODULE_AUTH; |
constant thread_safe=1; |
|
constant name = "method name"; |
|
User authenticate( RequestID id, UserDB db ); |
|
|
|
|
|
mapping authenticate_throw( RequestID id, string realm, UserDB db ); |
|
|
|
|
} |
|
protected mapping(string:function(void:void)) user_sql_inited = ([]); |
protected Sql.Sql user_mysql; |
protected void init_user_sql(string table) |
{ |
string db = all_constants()->REPLICATE?"replicate":"local"; |
if( !user_mysql ) |
user_mysql = master()->resolv("DBManager.get")( db ); |
if(catch(user_mysql->query( "SELECT module FROM "+ |
table+" WHERE module=''"))) |
{ |
user_mysql->query( "CREATE TABLE "+table+" " |
" (module varchar(30) NOT NULL, " |
" name varchar(30) NOT NULL, " |
" user varchar(30) NOT NULL, " |
" value blob, " |
" raw int not null, " |
" INDEX foo (module,name,user))" ); |
master()->resolv("DBManager.is_module_table")( 0, db, table, |
"Contains metadata about users. " |
"Userdatabases can store information here " |
"at the request of other modules, or they " |
"can keep their own state in this table" ); |
} |
user_sql_inited[ table ]= |
lambda(){user_mysql = master()->resolv("DBManager.get")( db );}; |
} |
|
|
class Group( UserDB database ) |
{ |
string name(); |
|
|
array(string) members() |
|
|
|
|
{ |
array res = ({}); |
User uid; |
int id = gid(); |
foreach( database->list_users(), string u ) |
if( (uid = database->find_user( u )) && |
((uid->gid() == id) || has_value(uid->groups(), name()))) |
res += ({ u }); |
return res; |
} |
|
int gid(); |
|
|
|
int set_name( string new_name ) { return 0; } |
int set_gid( int new_gid ) { return 0; } |
int set_members( array(string) members ) { return 0; } |
|
|
} |
|
#ifdef THREADS |
protected Thread.Mutex mutex = Thread.Mutex(); |
#endif |
|
|
class User( UserDB database ) |
{ |
protected string table; |
|
string name(); |
|
|
string real_name(); |
|
|
int password_authenticate(string password) |
|
|
{ |
string c = crypted_password(); |
return !sizeof(c) || crypt(password, c); |
} |
|
int uid(); |
|
|
int gid(); |
|
|
string shell(); |
|
|
string gecos() |
|
{ |
return real_name(); |
} |
|
string homedir(); |
string crypted_password() { return "x"; } |
|
|
array(string) groups() |
|
|
{ |
return ({}); |
} |
|
int set_name(string name) {} |
int set_real_name(string rname) {} |
int set_uid(int uid) {} |
int set_gid(int gid) {} |
int set_shell(string shell) {} |
int set_gecos(string gecos) {} |
int set_homedir(string hodir) {} |
int set_crypted_password(string passwd) {} |
int set_password(string passwd) {} |
|
|
array compat_userinfo( ) |
|
|
|
|
|
|
|
|
{ |
return ({name(),crypted_password(),uid(),gid(),gecos(),homedir(),shell()}); |
} |
|
|
#define INIT_SQL() do{ \ |
if(!table) table = replace(database->my_configuration()->name," ","_")+"_user_variables"; \ |
if(!user_sql_inited[ table ] )init_user_sql( table );else user_sql_inited[ table ](); \ |
} while( 0 ) |
|
|
#ifdef THREADS |
#define LOCK() mixed ___key = mutex->lock() |
#else |
#define LOCK() |
#endif |
|
protected string module_name( RoxenModule module ) |
{ |
if( !module ) |
|
|
return "'0'"; |
else |
return replace("'"+user_mysql->quote(module->sname())+"'","%","%%"); |
} |
|
mixed set_var( RoxenModule module, string index, mixed value ) |
|
|
|
|
|
|
|
|
|
|
|
{ |
delete_var( module, index ); |
mixed oval = value; |
LOCK(); |
INIT_SQL(); |
int encoded; |
|
if( stringp( value ) ) |
value = string_to_utf8( value ); |
else |
{ |
value = encode_value( value ); |
encoded = 1; |
} |
|
user_mysql->query( |
"INSERT INTO "+table+" (module,name,user,value,raw) " |
"VALUES ("+module_name( module )+", %s, %s, %s, %d)", |
index, name(), value, encoded |
); |
return oval; |
} |
|
mixed get_var( RoxenModule module, string index ) |
|
{ |
array rows; |
LOCK(); |
INIT_SQL(); |
rows = user_mysql->query( "SELECT * FROM "+table+ |
" WHERE module="+module_name( module ) |
+" AND name=%s AND user=%s", |
index, name() ); |
if( !sizeof( rows ) ) |
return 0; |
mapping m = rows[0]; |
|
if( (int)m->raw ) |
return decode_value( m->value ); |
return utf8_to_string( m->value ); |
} |
|
void delete_var( RoxenModule module, string index ) |
|
{ |
LOCK(); |
INIT_SQL(); |
user_mysql->query( "DELETE FROM "+table+" WHERE (module="+ |
module_name( module )+ |
" AND name=%s AND user=%s)", index, name() ); |
} |
#undef INIT_SQL |
#undef LOCK |
} |
|
class UserDB |
|
|
{ |
inherit RoxenModule; |
constant module_type = MODULE_USERDB; |
constant thread_safe=1; |
|
constant name = "db name"; |
|
User find_user( string s, RequestID|void id ); |
|
|
User find_user_from_uid( int uid, RequestID|void id ) |
|
|
{ |
User user; |
foreach( list_users(), string u ) |
if( (user = find_user( u )) && (user->uid() == uid) ) |
return user; |
} |
|
Group find_group( string group, RequestID|void id ) |
|
|
{ |
} |
|
Group find_group_from_gid( int gid, RequestID|void id ) |
|
|
{ |
Group group; |
foreach( list_groups(), string u ) |
if( (group = find_group( u )) && (group->gid() == gid) ) |
return group; |
} |
|
array(string) list_groups( RequestID|void id ) |
|
|
{ |
return ({}); |
} |
|
array(string) list_users( RequestID|void id ); |
|
|
User create_user( string s ) |
|
|
|
{ |
return 0; |
} |
|
Group create_group( string s ) |
|
|
|
{ |
return 0; |
} |
} |
|
|
|