97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | |
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
|
97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | |
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
inherit "module";
#include <module.h>
#include <request_trace.h>
|
97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | | constant cvs_version = "$Id$";
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | constant thread_safe = 1;
|
8df805 | 2004-06-01 | Jonas Wallden | | constant module_name = "WebDAV: Protocol support";
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | constant module_type = MODULE_FIRST;
constant module_doc = "Adds support for various HTTP extensions defined "
"in <a href='http://rfc.roxen.com/2518'>RFC 2518 (WEBDAV)</a>, such as "
"<b>PROPFIND</b> and <b>PROPPATCH</b>.";
|
ca0492 | 2003-12-22 | Henrik Grubbström (Grubba) | | #ifdef DAV_DEBUG
#define DAV_WERROR(X...) werror(X)
#else /* !DAV_DEBUG */
#define DAV_WERROR(X...)
#endif /* DAV_DEBUG */
|
27d875 | 2018-03-27 | Henrik Grubbström (Grubba) | | #ifdef IF_HEADER_DEBUG
#define IF_HDR_MSG(X...) werror (X)
#else
#define IF_HDR_MSG(X...)
#endif
|
17a69a | 2004-05-13 | Henrik Grubbström (Grubba) | |
#ifdef THREADS
#define LOCK(X) key=id->conf->_lock(X)
#define UNLOCK() do{key=0;}while(0)
#else
#define LOCK(X)
#define UNLOCK()
#endif
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | Configuration conf;
|
76c351 | 2004-05-14 | Henrik Grubbström (Grubba) | | void create()
{
defvar( "lock-timeout", 3600, "Default lock timeout", TYPE_INT,
|
8df805 | 2004-06-01 | Jonas Wallden | | "Number of seconds a WebDAV lock should by default be valid for. "
|
76c351 | 2004-05-14 | Henrik Grubbström (Grubba) | | "Negative disables locking. Zero means that locks default to "
"being valid for infinite duration." );
defvar( "max-lock-timeout", 86400, "Maximum lock timeout", TYPE_INT,
|
8df805 | 2004-06-01 | Jonas Wallden | | "Maximum number of seconds a WebDAV lock should be valid for. "
|
76c351 | 2004-05-14 | Henrik Grubbström (Grubba) | | "Negative disables the timeout header. "
"Zero enables infinite locks. " );
}
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | void start(int q, Configuration c)
{
conf = c;
}
|
27d875 | 2018-03-27 | Henrik Grubbström (Grubba) | | mapping(string:mixed)|int(-1..0) low_check_if_header(string path,
array(array(array(string))) condition,
RequestID id)
{
SIMPLE_TRACE_ENTER(this, "Checking \"If\" header for %O", path);
string|int(-1..0) etag;
mapping(string:DAVLock) locks;
next_condition:
foreach(condition, array(array(string)) sub_cond) {
SIMPLE_TRACE_ENTER(this,
"Trying condition ( %{%s:%O %})...", sub_cond);
int negate;
foreach(sub_cond, array(string) token) {
switch(token[0]) {
case "not":
negate = !negate;
break;
case "etag":
if (!etag) {
if (!stringp(etag = id->conf->query_property(path,
"DAV:getetag", id))) {
etag = -1;
}
IF_HDR_MSG("IF: Etag: %O.\n", etag);
}
if (etag != token[1]) {
if (!negate) {
TRACE_LEAVE("Etag mismatch.");
continue next_condition;
}
} else if (negate) {
TRACE_LEAVE("Matched negated etag.");
continue next_condition;
}
negate = 0;
break;
case "key":
if (!locks) {
locks = id->conf->find_locks(path, 0, 0, id);
}
if (negate) {
if (locks[token[1]]) {
TRACE_LEAVE("Matched negated lock.");
continue next_condition;
}
} else if (!locks[token[1]]) {
SIMPLE_TRACE_LEAVE("Lock mismatch for key %O.", token[1]);
continue next_condition;
}
negate = 0;
break;
default:
SIMPLE_TRACE_LEAVE("Unsupported condition: %s: %O.",
token[0], token[1]);
continue next_condition;
}
}
TRACE_LEAVE("Found match.");
TRACE_LEAVE("Ok%s.");
return 0;
}
TRACE_LEAVE("Precondition failed.");
return Roxen.http_status(Protocols.HTTP.HTTP_PRECOND_FAILED);
}
mapping(string:mixed)|int(-1..0) check_if_header(RequestID id)
{
mapping(string:array(array(array(string)))) if_data =
id->get_if_data();
if (!if_data) return 0;
foreach(if_data; string path; array(array(array(string))) condition) {
if (!path) continue;
mapping(string:mixed)|int(-1..0) res =
low_check_if_header(path, condition, id);
if (res) return res;
}
return 0;
}
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | mapping(string:mixed)|int(-1..0) first_try(RequestID id)
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | {
|
27d875 | 2018-03-27 | Henrik Grubbström (Grubba) | | if (id->misc->internal_get) return 0;
mapping(string:mixed)|int(-1..0) res = check_if_header(id);
if (res) {
return res;
}
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | switch(id->method) {
case "OPTIONS":
return ([ "type":"text/html",
"data":"",
"extra_heads":([
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | "Allow":"CHMOD,COPY,DELETE,GET,HEAD,MKCOL,MKDIR,MOVE,"
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | "MV,PING,POST,PROPFIND,PROPPATCH,PUT,OPTIONS",
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | "Public":"CHMOD,COPY,DELETE,GET,HEAD,MKCOL,MKDIR,MOVE,"
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | "MV,PING,POST,PROPFIND,PROPPATCH,PUT,OPTIONS",
"Accept-Ranges":"bytes",
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | | "DAV":"1,2",
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | ]),
]);
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | case "LOCK":
case "UNLOCK":
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | case "COPY":
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | case "MOVE":
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | case "DELETE":
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | case "PROPFIND":
case "PROPPATCH":
return handle_webdav(id);
}
return 0;
}
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected constant SimpleNode = Parser.XML.Tree.SimpleNode;
protected constant SimpleRootNode = Parser.XML.Tree.SimpleRootNode;
protected constant SimpleHeaderNode = Parser.XML.Tree.SimpleHeaderNode;
protected constant SimpleElementNode = Parser.XML.Tree.SimpleElementNode;
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | |
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
class PatchPropertySetCmd
{
|
d5fb85 | 2004-03-01 | Henrik Grubbström (Grubba) | | constant command="DAV:set";
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | string property_name;
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | string|array(SimpleNode) value;
|
fc4039 | 2008-08-15 | Martin Stjernholm | | protected void create(SimpleNode prop_node)
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | {
property_name = prop_node->get_full_name();
value = prop_node->get_children();
if ((sizeof(value) == 1) &&
(value[0]->get_node_type() == Parser.XML.Tree.XML_TEXT)) {
value = value[0]->get_text();
}
}
|
df0424 | 2004-03-16 | Henrik Grubbström (Grubba) | | mapping(string:mixed) execute(PropertySet context)
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | {
|
a2a437 | 2004-03-23 | Martin Stjernholm | | #ifdef REQUEST_TRACE
RequestID id = context->id;
SIMPLE_TRACE_ENTER (0, "Setting property %O to %O", property_name, value);
#endif
mapping(string:mixed) res = context->set_property(property_name, value);
|
fb6c43 | 2004-03-24 | Anders Johansson | | #ifdef REQUEST_TRACE
|
a2a437 | 2004-03-23 | Martin Stjernholm | | SIMPLE_TRACE_LEAVE (res ?
sprintf ("Got status %d: %O", res->error, res->rettext) :
"");
|
fb6c43 | 2004-03-24 | Anders Johansson | | #endif
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return res;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
}
|
d5fb85 | 2004-03-01 | Henrik Grubbström (Grubba) | | class PatchPropertyRemoveCmd(string property_name)
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | {
|
d5fb85 | 2004-03-01 | Henrik Grubbström (Grubba) | | constant command="DAV:remove";
|
0cb4c4 | 2004-03-15 | Martin Stjernholm | |
|
df0424 | 2004-03-16 | Henrik Grubbström (Grubba) | | mapping(string:mixed) execute(PropertySet context)
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | {
|
a2a437 | 2004-03-23 | Martin Stjernholm | | #ifdef REQUEST_TRACE
RequestID id = context->id;
SIMPLE_TRACE_ENTER (0, "Removing property %O", property_name);
#endif
mapping(string:mixed) res = context->remove_property(property_name);
|
fb6c43 | 2004-03-24 | Anders Johansson | | #ifdef REQUEST_TRACE
|
a2a437 | 2004-03-23 | Martin Stjernholm | | SIMPLE_TRACE_LEAVE (res ?
sprintf ("Got status %d: %O", res->error, res->rettext) :
"");
|
fb6c43 | 2004-03-24 | Anders Johansson | | #endif
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return res;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
}
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | mapping(string:mixed)|int(-1..0) handle_webdav(RequestID id)
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | {
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode xml_data;
|
e9ceb9 | 2004-06-02 | Martin Stjernholm | | SIMPLE_TRACE_ENTER(this, "Handle WEBDAV request %s...", id->method);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | if (catch { xml_data = id->get_xml_data(); }) {
TRACE_LEAVE("Malformed XML.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Malformed XML data.");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | if (!(< "LOCK", "UNLOCK", "COPY", "MOVE", "DELETE",
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | "PROPFIND", "PROPPATCH">)[id->method]) {
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("Not implemented.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(501, "Not implemented.");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | |
int depth;
if ((<"PROPFIND", "COPY", "MOVE", "DELETE", "LOCK">)[id->method]) {
depth = ([ "0":0, "1":1, "infinity":0x7fffffff, 0:0x7fffffff ])
[id->request_headers->depth &&
String.trim_whites(id->request_headers->depth)];
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | if (zero_type(depth)) {
TRACE_LEAVE(sprintf("Bad depth header: %O.",
id->request_headers->depth));
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Unsupported depth.");
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | }
|
97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | | switch(id->method) {
case "DELETE":
case "MOVE":
if (depth != 0x7fffffff) {
TRACE_LEAVE(sprintf("Bad depth header: %O.",
id->request_headers->depth));
return Roxen.http_status(400, "Unsupported depth.");
}
break;
case "COPY":
if (depth == 1) {
TRACE_LEAVE(sprintf("Bad depth header: %O.",
id->request_headers->depth));
return Roxen.http_status(400, "Unsupported depth.");
}
break;
}
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | } else if (id->request_headers->depth) {
}
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
|
17a69a | 2004-05-13 | Henrik Grubbström (Grubba) | | #ifdef URL_MODULES
foreach(conf->url_modules(), function funp)
{
PROF_ENTER(Roxen.get_owning_module(funp)->module_name,"url module");
#ifdef THREADS
Thread.MutexKey key;
#endif
LOCK(funp);
TRACE_ENTER("URL module", funp);
mapping(string:mixed)|object tmp=funp( id, id->not_query );
UNLOCK();
PROF_LEAVE(Roxen.get_owning_module(funp)->module_name,"url module");
if(mappingp(tmp))
{
TRACE_LEAVE("");
TRACE_LEAVE("Returning data");
return tmp;
}
if(objectp( tmp ))
{
mixed err;
err = catch {
tmp = id->conf->low_get_file( tmp, 1 );
};
if(err) throw(err);
TRACE_LEAVE("");
TRACE_LEAVE("Returning data");
return tmp;
}
TRACE_LEAVE("");
}
#endif
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
|
110814 | 2004-05-10 | Martin Stjernholm | | function(string,string,int,RoxenModule,RequestID,
|
c2025d | 2004-03-03 | Henrik Grubbström (Grubba) | | mixed ...:mapping(string:mixed)) recur_func;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | array(mixed) extras = ({});
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | mapping(string:mixed) empty_result;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | switch(id->method) {
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | case "LOCK":
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | DAVLock lock;
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | if (!xml_data) {
|
42e899 | 2004-05-07 | Martin Stjernholm | | int|DAVLock state =
|
356370 | 2004-05-03 | Henrik Grubbström (Grubba) | | id->conf->check_locks(id->not_query, 0, id);
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | if (intp(state)) {
if (state) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: Refresh: locked by other user.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(423, "Locked by other user");
} else {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: Refresh: Lock not found.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(424, "Couldn't refresh missing lock.");
}
}
|
7e8b92 | 2004-05-14 | Henrik Grubbström (Grubba) | | id->conf->refresh_lock(lock = state);
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | } else {
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode lock_info_node =
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | xml_data->get_first_element("DAV:lockinfo", 1);
if (!lock_info_node) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: No DAV:lockinfo.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(422, "Missing DAV:lockinfo.");
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode lock_scope_node =
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | lock_info_node->get_first_element("DAV:lockscope", 1);
if (!lock_scope_node) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: No DAV:lockscope.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(422, "Missing DAV:lockscope.");
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
string lockscope;
if (lock_scope_node->get_first_element("DAV:exclusive", 1)) {
lockscope = "DAV:exclusive";
}
if (lock_scope_node->get_first_element("DAV:shared", 1)) {
if (lockscope) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: Both DAV:exclusive and DAV:shared.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(422, "Both DAV:exclusive and DAV:shared.");
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
lockscope = "DAV:shared";
}
if (!lockscope) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: Both DAV:lockscope.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(422, "Unsupported DAV:lockscope.");
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode lock_type_node =
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | lock_info_node->get_first_element("DAV:locktype", 1);
if (!lock_type_node) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: Both DAV:locktype.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(422, "Missing DAV:locktype.");
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
if (!lock_type_node->get_first_element("DAV:write", 1)) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("LOCK: No DAV:write.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return Roxen.http_status(422, "Missing DAV:write.");
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
string locktype = "DAV:write";
|
bd9564 | 2004-05-06 | Martin Stjernholm | |
|
76c351 | 2004-05-14 | Henrik Grubbström (Grubba) | | int expiry_delta = query("lock-timeout");
if (expiry_delta < 0) {
TRACE_LEAVE("LOCK: Locks disabled.");
return Roxen.http_status(403, "Locking not allowed.");
}
if (id->request_headers->timeout) {
foreach(MIME.tokenize(id->request_headers->timeout),
string|int entry) {
if (intp(entry)) continue;
if (entry == "Infinite") {
if (!query("max-lock-timeout")) {
expiry_delta = 0;
break;
}
} else if (has_prefix(entry, "Second-")) {
int t;
if (sscanf(entry, "Second-%d", t) && (t > 0)) {
if (!query("max-lock-timeout") ||
(t < query("max-lock-timeout"))) {
expiry_delta = t;
break;
}
}
}
}
}
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | array(SimpleNode) owner;
if (SimpleNode owner_node = lock_info_node->get_first_element("DAV:owner", 1))
|
bd9564 | 2004-05-06 | Martin Stjernholm | | owner = owner_node->get_children();
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | |
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_ENTER(sprintf("LOCK: Creating a %s%s lock on %O.",
depth?"recursive ":"", lockscope, id->not_query),
this);
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | mapping(string:mixed)|DAVLock new_lock =
id->conf->lock_file(id->not_query,
depth != 0,
|
356370 | 2004-05-03 | Henrik Grubbström (Grubba) | | lockscope,
"DAV:write",
|
76c351 | 2004-05-14 | Henrik Grubbström (Grubba) | | expiry_delta,
|
bd9564 | 2004-05-06 | Martin Stjernholm | | owner,
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | id);
if (mappingp(new_lock)) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("Failed.");
TRACE_LEAVE("Returning failure code.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return new_lock;
}
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("Ok.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | lock = new_lock;
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | }
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | string xml = SimpleRootNode()->
add_child(SimpleHeaderNode((["version":"1.0", "encoding":"utf-8"])))->
add_child(SimpleElementNode("DAV:prop",
([ "xmlns:DAV":"DAV:",
"xmlns:MS":
"urn:schemas-microsoft-com:datatypes"
]))->
add_child(SimpleElementNode("DAV:lockdiscovery", ([]))->
add_child(lock->get_xml())))->render_xml();
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("Returning XML.");
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | return ([
"error":200,
"data":xml,
"len":sizeof(xml),
"type":"text/xml; charset=\"utf-8\"",
|
c057eb | 2004-05-06 | Henrik Grubbström (Grubba) | | "extra_heads":([ "Lock-Token":lock->locktoken ]),
|
103d3f | 2004-04-30 | Henrik Grubbström (Grubba) | | ]);
|
cf0907 | 2004-04-29 | Henrik Grubbström (Grubba) | | case "UNLOCK":
|
6b3422 | 2004-05-04 | Henrik Grubbström (Grubba) | | string locktoken;
if (!(locktoken = id->request_headers["lock-token"])) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("UNLOCK: No lock-token.");
|
6b3422 | 2004-05-04 | Henrik Grubbström (Grubba) | | return Roxen.http_status(400, "UNLOCK: Missing lock-token header.");
}
sscanf(locktoken, "<%s>", locktoken);
|
7ee0b0 | 2018-03-27 | Henrik Grubbström (Grubba) | | string path = id->not_query;
if (!has_suffix(path, "/")) path += "/";
mapping(string:DAVLock) locks = id->conf->find_locks(path, 0, 1, id);
if (!(lock = locks[locktoken])) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE(sprintf("UNLOCK: Lock-token %O not found.", locktoken));
|
6b3422 | 2004-05-04 | Henrik Grubbström (Grubba) | | return Roxen.http_status(403, "UNLOCK: Lock not found.");
}
|
7ee0b0 | 2018-03-27 | Henrik Grubbström (Grubba) | | if (lock->path != path) {
SIMPLE_TRACE_LEAVE("UNLOCK: Lock doesn't match path: %O != %O.\n",
path, lock->path);
|
676103 | 2004-05-10 | Henrik Grubbström (Grubba) | | return Roxen.http_status(423, "Invalid locktoken.");
}
|
7ee0b0 | 2018-03-27 | Henrik Grubbström (Grubba) | | mapping res = id->conf->unlock_file(path, lock, id);
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | if (res) {
TRACE_LEAVE(sprintf("UNLOCK: Unlocking of %O failed.", locktoken));
return res;
}
TRACE_LEAVE(sprintf("UNLOCK: Unlocked %O successfully.", locktoken));
return Roxen.http_status(204, "Ok.");
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | case "COPY":
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | case "MOVE":
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | if (!id->request_headers->destination) {
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_LEAVE("%s: No destination header.", id->method);
return Roxen.http_status(400,
sprintf("%s: Missing destination header.",
id->method));
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | }
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | PropertyBehavior propertybehavior = (<>);
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | if (xml_data) {
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | |
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | |
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode prop_behav_node =
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | xml_data->get_first_element("DAV:propertybehavior", 1);
if (!prop_behav_node) {
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_LEAVE("%s: No DAV:propertybehavior.", id->method);
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Missing DAV:propertybehavior.");
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | }
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | foreach(prop_behav_node->get_children(), SimpleNode n) {
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | switch(n->get_full_name()) {
case "DAV:omit":
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | if (!multisetp(propertybehavior) || sizeof(propertybehavior)) {
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Conflicting DAV:propertybehavior.");
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | }
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | propertybehavior = 0;
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | break;
case "DAV:keepalive":
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | if (!multisetp(propertybehavior) || sizeof(propertybehavior)) {
return Roxen.http_status(400, "Conflicting DAV:propertybehavior.");
}
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | foreach(n->get_children(), SimpleNode href) {
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | if (href->get_full_name == "DAV:href") {
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | if (!multisetp(propertybehavior)) {
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_LEAVE("%s: Conflicting DAV:propertybehaviour.",
id->method);
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | return Roxen.http_status(400,
"Conflicting DAV:propertybehavior.");
}
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | propertybehavior[href->value_of_node()] = 1;
} else if (href->mNodeType == Parser.XML.Tree.XML_TEXT) {
if (href->get_text() != "*"){
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_LEAVE("%s: Syntax error in DAV:keepalive.",
id->method);
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | return Roxen.http_status(400,
"Syntax error in DAV:keepalive.");
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | }
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | if (!multisetp(propertybehavior) || sizeof(propertybehavior)) {
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_LEAVE("%s: Conflicting DAV:propertybehaviour.",
id->method);
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | return Roxen.http_status(400,
"Conflicting DAV:propertybehavior.");
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | }
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | propertybehavior = 1;
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | }
}
break;
}
}
}
|
545f5f | 2004-05-10 | Henrik Grubbström (Grubba) | | extras = ({ id->misc["new-uri"],
propertybehavior,
|
aaed92 | 2004-05-13 | Martin Stjernholm | |
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | | (!id->request_headers->overwrite ||
id->request_headers->overwrite=="T")?
DO_OVERWRITE:NEVER_OVERWRITE,
|
545f5f | 2004-05-10 | Henrik Grubbström (Grubba) | | });
|
dc50a6 | 2004-05-13 | Henrik Grubbström (Grubba) | |
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | | recur_func = lambda(string source, string loc, int d, RoxenModule module,
|
110814 | 2004-05-10 | Martin Stjernholm | | RequestID id, string destination,
|
dfc1ad | 2004-05-13 | Henrik Grubbström (Grubba) | | PropertyBehavior behavior,
|
aaed92 | 2004-05-13 | Martin Stjernholm | | Overwrite overwrite) {
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | | if (!has_prefix(destination, loc)) {
return 0;
}
destination = destination[sizeof(loc)..];
|
97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | | mapping(string:mixed) res;
if (id->method == "MOVE") {
res = module->recurse_move_files(source, destination,
behavior, overwrite, id);
} else {
res = module->recurse_copy_files(source, destination,
behavior, overwrite, id,
!d);
}
|
d5432b | 2004-05-10 | Henrik Grubbström (Grubba) | | if (res && ((res->error == 201) || (res->error == 204))) {
empty_result = res;
|
86ed0b | 2018-02-02 | Henrik Grubbström (Grubba) | | if (id->method == "MOVE") {
|
da6048 | 2018-03-27 | Henrik Grubbström (Grubba) | | mapping(string:DAVLock) sub_locks =
|
52ab68 | 2018-02-02 | Jonas Walldén | | module->find_locks(source, -1, 0, id);
|
da6048 | 2018-03-27 | Henrik Grubbström (Grubba) | | foreach(sub_locks||([]);;DAVLock lock) {
|
86ed0b | 2018-02-02 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_ENTER(module,
"MOVE: Unlocking %O...", lock);
mapping fail =
id->conf->unlock_file(lock->path, lock, id);
if (fail) {
TRACE_LEAVE("MOVE: Unlock failed.");
} else {
TRACE_LEAVE("MOVE: Unlock ok.");
}
}
}
|
d5432b | 2004-05-10 | Henrik Grubbström (Grubba) | | return 0;
}
|
b629f7 | 2004-05-13 | Martin Stjernholm | | else if (!res && id->misc->error_code) {
empty_result = Roxen.http_status(id->misc->error_code);
}
|
d5432b | 2004-05-10 | Henrik Grubbström (Grubba) | | return res;
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | };
|
d5432b | 2004-05-10 | Henrik Grubbström (Grubba) | | empty_result = Roxen.http_status(404);
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | break;
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | case "DELETE":
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | | recur_func = lambda(string path, string ignored, int d, RoxenModule module,
|
110814 | 2004-05-10 | Martin Stjernholm | | RequestID id) {
mapping res = module->recurse_delete_files(path, id);
|
676103 | 2004-05-10 | Henrik Grubbström (Grubba) | | if (res && res->error < 300) {
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | |
|
676103 | 2004-05-10 | Henrik Grubbström (Grubba) | | empty_result = res;
|
69a7f2 | 2018-02-01 | Henrik Grubbström (Grubba) | |
|
da6048 | 2018-03-27 | Henrik Grubbström (Grubba) | | mapping(string:DAVLock) sub_locks =
|
69a7f2 | 2018-02-01 | Henrik Grubbström (Grubba) | | module->find_locks(path, -1, 0, id);
|
da6048 | 2018-03-27 | Henrik Grubbström (Grubba) | | foreach(sub_locks||([]);;DAVLock lock) {
|
69a7f2 | 2018-02-01 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_ENTER(module,
"DELETE: Unlocking %O...", lock);
mapping fail =
id->conf->unlock_file(lock->path, lock, id);
if (fail) {
TRACE_LEAVE("DELETE: Unlock failed.");
} else {
TRACE_LEAVE("DELETE: Unlock ok.");
}
}
|
676103 | 2004-05-10 | Henrik Grubbström (Grubba) | | return 0;
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | | }
|
676103 | 2004-05-10 | Henrik Grubbström (Grubba) | | return res;
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | };
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | |
empty_result = Roxen.http_status(404);
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | break;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | case "PROPFIND":
if (xml_data) {
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode propfind = xml_data->get_first_element("DAV:propfind", 1);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | if (!propfind) {
|
951dce | 2004-05-10 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("PROPFIND: No DAV:propfind.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Missing DAV:propfind.");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | foreach(propfind->get_children(), SimpleNode prop) {
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | switch(prop->get_full_name()) {
case "DAV:propname":
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | if (recur_func) {
TRACE_LEAVE("PROPFIND: Conflicting DAV:propfind.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Bad DAV request (23.3.2.1).");
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | }
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | recur_func = lambda(string path, string ignored, int d,
|
110814 | 2004-05-10 | Martin Stjernholm | | RoxenModule module, RequestID id) {
|
e9ceb9 | 2004-06-02 | Martin Stjernholm | | return module->recurse_find_properties(path,
"DAV:propname",
d, id);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | };
break;
case "DAV:allprop":
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | if (recur_func) {
TRACE_LEAVE("PROPFIND: Conflicting DAV:propfind.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Bad DAV request (23.3.2.1).");
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | }
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | recur_func = lambda(string path, string ignored, int d,
|
110814 | 2004-05-10 | Martin Stjernholm | | RoxenModule module, RequestID id,
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | multiset(string)|void filt) {
|
e9ceb9 | 2004-06-02 | Martin Stjernholm | | return module->recurse_find_properties(path,
"DAV:allprop",
d, id,
filt);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | };
break;
case "DAV:prop":
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | if (recur_func) {
TRACE_LEAVE("PROPFIND: Conflicting DAV:propfind.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Bad DAV request (23.3.2.1).");
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | }
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | recur_func = lambda(string path, string ignored, int d,
|
110814 | 2004-05-10 | Martin Stjernholm | | RoxenModule module, RequestID id,
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | multiset(string) filt) {
|
e9ceb9 | 2004-06-02 | Martin Stjernholm | | return module->recurse_find_properties(path,
"DAV:prop",
d, id,
filt);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | };
case "http://sapportals.com/xmlns/cm/webdavinclude":
multiset(string) props =
(multiset(string))(prop->get_children()->get_full_name() -
({ "" }));
if (sizeof(extras)) {
extras[0] |= props;
} else {
extras = ({ props });
}
break;
default:
break;
}
}
} else {
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | recur_func = lambda(string path, string ignored, int d,
|
110814 | 2004-05-10 | Martin Stjernholm | | RoxenModule module, RequestID id) {
|
e9ceb9 | 2004-06-02 | Martin Stjernholm | | return module->recurse_find_properties(path,
"DAV:allprop",
d, id);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | };
}
break;
case "PROPPATCH":
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode propupdate = xml_data->get_first_element("DAV:propertyupdate", 1);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | if (!propupdate) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("PROPPATCH: No DAV:propertyupdate.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Missing DAV:propertyupdate.");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
array(PatchPropertyCommand) instructions = ({});
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | foreach(propupdate->get_children(), SimpleNode cmd) {
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | switch(cmd->get_full_name()) {
case "DAV:set":
case "DAV:remove":
|
a8e2b3 | 2004-05-07 | Henrik Grubbström (Grubba) | | SimpleNode prop = cmd->get_first_element("DAV:prop", 1);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | if (!prop) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("PROPPATCH: No DAV:prop.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Bad DAV request (no properties specified).");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
if (cmd->get_full_name() == "DAV:set") {
instructions += map(prop->get_children(), PatchPropertySetCmd);
} else {
instructions += map(prop->get_children()->get_full_name(),
PatchPropertyRemoveCmd);
}
break;
default:
break;
}
}
if (!sizeof(instructions)) {
|
c28075 | 2004-05-04 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("PROPPATCH: No instructions.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Bad DAV request (23.3.2.2).");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | recur_func = lambda(string path, string ignored, int d, RoxenModule module,
|
110814 | 2004-05-10 | Martin Stjernholm | | RequestID id,
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | array(PatchPropertyCommand) instructions) {
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | |
|
110814 | 2004-05-10 | Martin Stjernholm | | return module->patch_properties(path, instructions, id);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | };
extras = ({ instructions });
break;
default:
break;
}
if (!recur_func) {
TRACE_LEAVE("Bad DAV request.");
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return Roxen.http_status(400, "Bad DAV request (23.3.2.2).");
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|
9c5c12 | 2004-05-05 | Martin Stjernholm | | int start_ms_size = id->multi_status_size();
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | string href = id->not_query;
string href_prefix = combine_path(href, "./");
|
b8f627 | 2010-06-28 | Martin Jonsson | | RoxenModule opaque_module;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | foreach(conf->location_modules(), [string loc, function fun]) {
int d = depth;
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | string path;
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | | SIMPLE_TRACE_ENTER(function_object(fun),
"Trying module mounted at %O...", loc);
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | | if (has_prefix(href, loc) || (loc == href+"/")) {
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
path = href[sizeof(loc)..];
|
97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | | } else if (d && has_prefix(loc, href_prefix)) {
|
179585 | 2004-05-08 | Henrik Grubbström (Grubba) | |
|
97e503 | 2018-03-20 | Henrik Grubbström (Grubba) | | d -= sizeof((loc[sizeof(href_prefix)..])/"/");
if (d < 0) continue;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | |
path = "";
} else {
TRACE_LEAVE("Miss");
continue;
}
#ifdef MODULE_LEVEL_SECURITY
int|mapping security_ret;
if(security_ret = conf->check_security(fun, id)) {
if (mappingp(security_ret)) {
|
a37842 | 2004-03-01 | Henrik Grubbström (Grubba) | |
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("Security check return.");
TRACE_LEAVE("Need authentication.");
|
9c5c12 | 2004-05-05 | Martin Stjernholm | | recur_func = 0;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | return security_ret;
} else {
TRACE_LEAVE("Not allowed.");
continue;
}
}
#endif
RoxenModule c = function_object(fun);
|
b8f627 | 2010-06-28 | Martin Jonsson | | if (c->webdav_opaque) opaque_module = c;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | TRACE_ENTER("Performing the work...", c);
|
9c5c12 | 2004-05-05 | Martin Stjernholm | | ASSERT_IF_DEBUG (has_prefix (loc, "/"));
|
110814 | 2004-05-10 | Martin Stjernholm | | mapping(string:mixed) ret = recur_func(path, loc, d, c, id, @extras);
|
c2025d | 2004-03-03 | Henrik Grubbström (Grubba) | | if (ret) {
TRACE_LEAVE("Short circuit return.");
TRACE_LEAVE("Done.");
TRACE_LEAVE("DAV request done.");
|
9c5c12 | 2004-05-05 | Martin Stjernholm | | recur_func = 0;
|
c2025d | 2004-03-03 | Henrik Grubbström (Grubba) | | return ret;
}
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | TRACE_LEAVE("Done.");
TRACE_LEAVE("Done.");
|
b8f627 | 2010-06-28 | Martin Jonsson | | if (opaque_module) break;
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|
b8f627 | 2010-06-28 | Martin Jonsson | | if (opaque_module)
TRACE_LEAVE(sprintf("DAV request done (returned early after %O).",
opaque_module));
else
TRACE_LEAVE("DAV request done.");
|
9c5c12 | 2004-05-05 | Martin Stjernholm | | recur_func = 0;
if (id->multi_status_size() == start_ms_size) {
|
a2a437 | 2004-03-23 | Martin Stjernholm | | return empty_result || Roxen.http_status(404);
|
63a38c | 2004-03-03 | Henrik Grubbström (Grubba) | | }
|
9c5c12 | 2004-05-05 | Martin Stjernholm | | return ([]);
|
5496fd | 2003-09-17 | Henrik Grubbström (Grubba) | | }
|