~ubuntu-branches/ubuntu/hardy/steam/hardy

« back to all changes in this revision

Viewing changes to server/net/webdav.pike

  • Committer: Bazaar Package Importer
  • Author(s): Alain Schroeder
  • Date: 2006-11-21 16:03:12 UTC
  • mfrom: (2.1.4 feisty)
  • Revision ID: james.westby@ubuntu.com-20061121160312-nf96y6nihzsyd2uv
Tags: 2.2.31-3
Add patch to prevent inconsistent data after shutdown.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2004  Thomas Bopp, Thorsten Hampel, Ludger Merkens
 
1
/* Copyright (C) 2000-2006  Thomas Bopp, Thorsten Hampel, Ludger Merkens
2
2
 *
3
3
 *  This program is free software; you can redistribute it and/or modify
4
4
 *  it under the terms of the GNU General Public License as published by
14
14
 *  along with this program; if not, write to the Free Software
15
15
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
16
 * 
17
 
 * $Id: webdav.pike,v 1.1.1.1 2005/02/23 14:47:21 cvs Exp $
18
 
 */
19
 
 
20
 
constant cvs_version="$Id: webdav.pike,v 1.1.1.1 2005/02/23 14:47:21 cvs Exp $";
21
 
 
22
 
/* BUGS/PROBLEMS
23
 
 * - PUT method does not return correct response (at least on IE)
24
 
 * - IE asks for overwritting existing file even if file is not present
25
 
 */
26
 
 
 
17
 * $Id: webdav.pike,v 1.3 2006/05/17 20:41:49 exodusd Exp $
 
18
 */
 
19
 
 
20
constant cvs_version="$Id: webdav.pike,v 1.3 2006/05/17 20:41:49 exodusd Exp $";
27
21
 
28
22
inherit "http";
29
23
 
32
26
#include <macros.h>
33
27
#include <classes.h>
34
28
#include <attributes.h>
 
29
#include <config.h>
 
30
#include <database.h>
35
31
 
36
32
//#define WEBDAV_DEBUG
37
33
 
41
37
#define DAV_WERR(s, args...)
42
38
#endif
43
39
 
44
 
//#define CLASS2 
 
40
import httplib;
 
41
 
45
42
 
46
43
class steamDAV {
47
44
  inherit WebdavHandler;
55
52
    _dav = dav;
56
53
    __fp = fp;
57
54
  }
58
 
 
59
 
  void lock(mixed ctx, string fname, mapping lock_data) {
60
 
    if ( objectp(ctx) )
61
 
      ctx->set_attribute(OBJ_LOCK, lock_data);
62
 
    else
63
 
      null_ressources[fname] = lock_data | ([ "isnull": 1, ]) ;
64
 
  }
65
 
  mapping is_locked(mixed ctx, string fname) {
66
 
    if ( !objectp(ctx) ) {
67
 
      return null_ressources[fname];
68
 
    }
69
 
    return ctx->query_attribute(OBJ_LOCK);
70
 
  }
71
 
 
 
55
  string url_name(string fname) {
 
56
      return replace_uml(fname);
 
57
  }
 
58
 
 
59
  static string generate_token(object ctx) {
 
60
    int id = 0;
 
61
    
 
62
    if ( objectp(ctx) ) 
 
63
      id = ctx->get_object_id();
 
64
    
 
65
    string token = sprintf("%08x", random(time()));
 
66
    string ttoken = sprintf("%08x", time())  + sprintf("%08x", random(time())) + sprintf("%08x", random(time()));
 
67
    
 
68
    return "opaquelocktoken:" + token + "-" + 
 
69
      ttoken[0..3] + "-" + ttoken[4..7] + "-" + ttoken[8..11] + "-" +
 
70
      ttoken[12..];
 
71
  }
 
72
 
 
73
  string lock(mixed ctx, string fname, mapping lock_data) {
 
74
    string token;
 
75
 
 
76
    if ( !lock_data->token ) {
 
77
        token = generate_token(ctx);
 
78
        lock_data->token = token;
 
79
    }
 
80
    else
 
81
        token = lock_data->token;
 
82
    
 
83
    if ( objectp(ctx) ) {
 
84
        mapping ldata = ctx->query_attribute(OBJ_LOCK) || ([ ]);
 
85
        ldata[token] = lock_data;
 
86
        ctx->set_attribute(OBJ_LOCK, ldata);
 
87
    }
 
88
    else {
 
89
        mapping ldata = null_ressources[fname];
 
90
        ldata[token] = lock_data;
 
91
        null_ressources[fname] = ldata | ([ "isnull": 1, ]) ;
 
92
    }
 
93
    return lock_data->token;
 
94
  }
 
95
  void unlock(mixed ctx, string fname, void|string token)
 
96
  {
 
97
      if ( !stringp(token) )
 
98
          ctx->set_attribute(OBJ_LOCK, 0);
 
99
      else {
 
100
          mapping ldata = ctx->query_attribute(OBJ_LOCK);
 
101
          if ( mappingp(ldata) ) {
 
102
              m_delete(ldata, token);
 
103
              ctx->set_attribute(OBJ_LOCK, ldata);
 
104
          }
 
105
      }
 
106
  }
 
107
  mapping get_locks(mixed ctx, string fname) {
 
108
      if ( !objectp(ctx) )
 
109
          return null_ressources[fname];
 
110
      return ctx->query_attribute(OBJ_LOCK) || ([ ]);
 
111
  }
 
112
  mapping is_locked(mixed ctx, string fname, void|string gottoken) {
 
113
    mapping ldata;
 
114
    if ( !objectp(ctx) ) 
 
115
        ldata =  null_ressources[fname] || ([ ]);
 
116
    else
 
117
        ldata = ctx->query_attribute(OBJ_LOCK) || ([ ]);
 
118
    DAV_WERR("is_locked(%O, %s)", ctx, fname);
 
119
    
 
120
    foreach(indices(ldata), string token) {
 
121
        mapping lockdata = ldata[token];
 
122
        if ( mappingp(lockdata) ) {
 
123
            int timeout = 180;
 
124
            if ( stringp(lockdata["timeout"]) ) {
 
125
                sscanf(lockdata["timeout"], "Second-%d", timeout);
 
126
            }
 
127
            if ( lockdata->locktime > 0 && (time() - lockdata->locktime) < timeout )
 
128
            {
 
129
                DAV_WERR("active lock found...");
 
130
                if ( !stringp(gottoken) || lockdata->token == gottoken )
 
131
                    return lockdata;
 
132
            }
 
133
        }
 
134
    }
 
135
    if ( objectp(ctx) ) {
 
136
        object env = ctx->get_environment();
 
137
        ldata = is_locked(env, "", gottoken);
 
138
        if ( mappingp(ldata) )
 
139
            return ldata;
 
140
    }
 
141
    if ( !stringp(gottoken) ) {
 
142
        if ( objectp(ctx) )
 
143
            ctx->set_attribute(OBJ_LOCK, 0);
 
144
        else
 
145
            null_ressources[fname] = 0;
 
146
    }
 
147
    return 0;
 
148
  }
 
149
  string get_user_href() {
 
150
    return _Server->get_server_name() + "/~" + this_user()->get_user_name();
 
151
  }
 
152
 
 
153
  string get_etag(mixed ctx) {
 
154
    return ctx->get_etag();
 
155
  }
72
156
 
73
157
  object get_object_id() { return _dav->get_object_id(); }
74
158
  object this() { return _dav->get_user_object(); }
76
160
 
77
161
static object __webdavHandler;
78
162
 
 
163
int check_lock(object obj, mapping vars, void|string fname) 
 
164
{
 
165
    if ( !objectp(obj) && !stringp(fname) )
 
166
        return 1;
 
167
    if ( !stringp(fname) )
 
168
        fname = "";
 
169
    string token = get_opaquelocktoken(__request->request_headers->if);
 
170
    if ( stringp(token) ) {
 
171
        if ( mappingp(__webdavHandler->is_locked(obj, fname, token)) )
 
172
            return 1;
 
173
    }
 
174
    mapping res = __webdavHandler->is_locked(obj, fname);
 
175
    DAV_WERR("Checking lock (current token=%O) locked=%O", token, res);
 
176
    return res == 0;
 
177
}
 
178
 
79
179
mapping handle_OPTIONS(object obj, mapping variables)
80
180
{       
81
181
    mapping result = ::handle_OPTIONS(obj, variables);
82
182
    result->extra_heads += ([ 
83
183
        "MS-Author-Via": "DAV",
84
 
#ifdef CLASS2
85
 
        "DAV": "2",
 
184
#ifdef WEBDAV_CLASS2
 
185
        "DAV": "1,2",
86
186
#else
87
187
        "DAV": "1", 
88
188
#endif
89
189
    ]);
90
 
        
91
190
    return result;
92
191
}
93
192
 
94
 
#ifdef CLASS2
 
193
#ifdef WEBDAV_CLASS2
95
194
mapping handle_LOCK(object obj, mapping variables)
96
195
{
97
 
  return lock(__request->not_query, __request->request_headers, 
98
 
              __request->body_raw,
99
 
              __webdavHandler, obj);
100
 
}
 
196
    if ( this_user() == USER("guest") )
 
197
        return response_noaccess(obj, variables);
 
198
    obj = _fp->path_to_object(__request->not_query, 1);
101
199
 
102
 
mapping handle_UNLOCK(object obj, mapping variables)
103
 
{
104
 
  return unlock(__request->not_query, __request->request_headers,
 
200
    return lock(__request->not_query, __request->request_headers, 
105
201
                __request->body_raw,
106
202
                __webdavHandler, obj);
107
203
}
 
204
 
 
205
mapping handle_UNLOCK(object obj, mapping variables)
 
206
{
 
207
    if ( this_user() == USER("guest") )
 
208
        return response_noaccess(obj, variables);
 
209
    obj = _fp->path_to_object(__request->not_query, 1);
 
210
 
 
211
    return unlock(__request->not_query, __request->request_headers,
 
212
                  __request->body_raw,
 
213
                  __webdavHandler, obj);
 
214
}
108
215
#endif
109
216
 
110
217
static bool move_and_rename(object obj, string name)
111
218
{
112
 
    string fname, dname;
 
219
    string fname, dname, sname;
 
220
 
 
221
    sname = _Server->get_server_name();
 
222
    sscanf(name, "%*s://" + _Server->get_server_name() + "%s", name);
113
223
 
114
224
    if ( name[-1] == '/' )
115
225
      name = dirname(name);
121
231
      DAV_WERR("No Target directory found at %s", dname);
122
232
      return false;
123
233
    }
124
 
    obj->move(target);
125
234
    if ( strlen(fname) > 0 ) 
126
235
      obj->set_attribute(OBJ_NAME, fname);
 
236
    obj->move(target);
127
237
    return true;
128
238
}
129
239
 
132
242
    string destination = __request->request_headers->destination;
133
243
    string overwrite   = __request->request_headers->overwrite;
134
244
 
135
 
    if ( objectp(obj) && obj->is_locked(DOC_LAST_MODIFIED) )
136
 
      return response_locked(__request->not_query);
 
245
    if ( !check_lock(obj, variables) ) 
 
246
        return low_answer(423, "Locked");
137
247
 
138
248
    if ( !stringp(overwrite) )
139
249
        overwrite = "T";
149
259
        __request->misc["new-uri"] = __request->misc->destination;
150
260
    DAV_WERR("Handling move:misc=\n"+sprintf("%O\n", __request->misc));
151
261
    
152
 
    object dest = _fp->path_to_object(__request->misc["new-uri"]);
 
262
    destination = __request->misc["new-uri"];
 
263
    if ( catch(destination = url_to_string(destination)) )
 
264
        FATAL("Failed to convert destination %s", destination);
 
265
    
 
266
    object dest = _fp->path_to_object(destination);
153
267
    if ( objectp(dest) ) {
154
268
      if ( __request->misc->overwrite == "F" ) {
155
269
        DAV_WERR("overwritting failed !");
156
270
        return low_answer(412, "Pre-Condition Failed");
157
271
      }
158
272
      else {
159
 
        res = 204;
160
 
        dest->delete();
 
273
          if ( !check_lock(dest, variables) )
 
274
              return low_answer(423, "Locked");
 
275
          res = 204;
 
276
          dest->delete();
161
277
      }
162
278
    }    
163
 
    if ( !move_and_rename(obj, __request->misc["new-uri"]) ) 
 
279
    if ( !move_and_rename(obj, destination) ) 
164
280
      return low_answer(409, "conflict");
165
281
    return low_answer(res, "moved");
166
282
}
182
298
    string overwrite   = __request->request_headers->overwrite;
183
299
    string dest_host;
184
300
 
 
301
 
185
302
    if ( !stringp(overwrite) )
186
303
        overwrite = "T";
187
304
    __request->misc->overwrite = overwrite;
205
322
        return low_answer(412, "conflict");
206
323
      }
207
324
      else {
208
 
        res = 204;
209
 
        duplicate->delete();
 
325
          if ( !check_lock(duplicate, variables) )
 
326
              return low_answer(423, "Locked");
 
327
          res = 204;
 
328
          duplicate->delete();
210
329
      }
211
330
    }    
212
331
    if ( objectp(obj) ) 
213
 
      {
 
332
    {
214
333
        if ( obj->get_object_class() & CLASS_CONTAINER )
215
334
          duplicate = obj->duplicate(true);
216
335
        else
219
338
        // dirname and fname
220
339
        if ( !move_and_rename(duplicate, __request->misc->destination) )
221
340
          return low_answer(409, "conflict");
 
341
        duplicate->set_attribute(OBJ_LOCK, 0);
222
342
        return low_answer(res, "copied");
223
 
      }
 
343
    }
224
344
    else {
225
 
      return low_answer(404, "not found");
 
345
        FATAL("Resource could not be found !");
 
346
        return low_answer(404, "not found");
226
347
    }
227
348
}
228
349
 
229
350
mapping|void handle_PROPPATCH(object obj, mapping variables)
230
351
{
 
352
    obj = _fp->path_to_object(__request->not_query, 1);
 
353
 
 
354
    if ( !check_lock(obj, variables) ) 
 
355
        return low_answer(423, "Locked");
 
356
 
231
357
    return proppatch(__request->not_query, __request->request_headers,
232
358
                     __request->body_raw, __webdavHandler, obj);
233
359
}
234
360
 
 
361
mapping handle_DELETE(object obj, mapping vars)
 
362
{
 
363
 
 
364
    if ( !check_lock(obj, vars) ) 
 
365
        return low_answer(423, "Locked");
 
366
    return ::handle_DELETE(obj, vars);
 
367
}
 
368
 
 
369
mapping handle_PUT(object obj, mapping vars)
 
370
{
 
371
    string fname = __request->not_query;
 
372
 
 
373
    obj = _fp->path_to_object(__request->not_query, 1);
 
374
 
 
375
        
 
376
    if ( !check_lock(obj, vars, fname) ) 
 
377
        return low_answer(423, "Locked");
 
378
    
 
379
    mapping result = ::handle_PUT(obj, vars);
 
380
    mixed err = catch {
 
381
        mapping locks = __webdavHandler->get_locks(0, fname);
 
382
        if ( mappingp(locks) && sizeof(locks) > 0 ) {
 
383
            // locked null resources
 
384
            object fp = vars->fp;
 
385
            if ( !objectp(fp) )
 
386
            fp = get_module("filepath:tree");
 
387
            obj = fp->path_to_object(fname);
 
388
            if ( objectp(obj) ) {
 
389
                if ( !mappingp(obj->query_attribute(OBJ_LOCK)) )
 
390
                    obj->set_attribute(OBJ_LOCK, locks);
 
391
            }
 
392
        }
 
393
    };
 
394
    if ( err ) {
 
395
        FATAL("While setting lock for previous null resource: %O", err);
 
396
    }
 
397
    return result;
 
398
}
 
399
 
235
400
mapping|void handle_PROPFIND(object obj, mapping variables)
236
401
{
237
 
  werror("handle_PROPFIND("+(objectp(obj) ? obj->describe() : "none")+")\n");
238
 
  if ( !objectp(obj) )
239
 
    return low_answer(404, "not found");
240
 
  return propfind(__request->not_query, __request->request_headers, 
241
 
                  __request->body_raw, __webdavHandler, obj);
 
402
    isWebDAV = 1; // heuristics ;-)
 
403
    
 
404
    obj = _fp->path_to_object(__request->not_query, 1);
 
405
    
 
406
    if ( !objectp(obj) )
 
407
        return low_answer(404, "not found");
 
408
    
 
409
    return propfind(__request->not_query, __request->request_headers, 
 
410
                    __request->body_raw, __webdavHandler, obj);
242
411
}    
243
412
 
244
413
mixed get_property(object obj, Property property)
245
414
{
 
415
  if ( !objectp(obj) )
 
416
    return 0;
246
417
  if ( !objectp(property) )
247
418
    error("No property found, null-pointer !");
248
419
  DAV_WERR("Get property %s, val=%O, ns=%O", property->get_name(),obj->query_attribute(property->get_name()), property->describe_namespace());
249
420
  string pname = property->get_ns_name();
 
421
 
250
422
#if 0
251
423
  switch( property->get_name() ) {
252
424
  case "displayname":
297
469
    mapping result = ([ ]);
298
470
 
299
471
    // overwritten - must not forward requests without trailing /
300
 
    DAV_WERR("DAV: %s %s", cmd, __request->not_query);
301
 
 
302
 
 
 
472
    DAV_WERR("RAW: %s", __request->raw);
 
473
    float f = gauge {
303
474
    function call = this_object()["handle_"+cmd];
304
475
    if ( functionp(call) ) {
305
476
        result = call(obj, variables);
308
479
        result->error = 501;
309
480
        result->data = "Not implemented";
310
481
    }
 
482
    if ( mappingp(result) ) {
 
483
      if ( stringp(result->data) && strlen(result->data) > 0 && 
 
484
           !result->encoding && !result->type ) 
 
485
      {
 
486
        result->tags = 0;
 
487
        result->encoding = "utf-8";
 
488
        result->type = "text/xml";
 
489
      }
 
490
    }
 
491
    };
 
492
    
 
493
    DAV_WERR("DAV: %s %s %f seconds", cmd, __request->not_query, f);
311
494
    return result;
312
495
}
313
496
 
326
509
 
327
510
void respond(object req, mapping result)
328
511
{
 
512
    DAV_WERR("Respond: %O", result);
329
513
    if ( stringp(result->data) )
330
514
        result->length = strlen(result->data);
 
515
 
331
516
    ::respond(req, result);
332
517
}
 
518
 
 
519
string get_identifier() 
 
520
 
521
    if ( is_dav() ) 
 
522
        return "webdav"; 
 
523
    else
 
524
        return "http";
 
525
}
 
526
 
 
527
string get_socket_name() { if ( is_dav() ) return "webdav"; else return "http"; }