]> err.no Git - sope/commitdiff
improved WebDAV layer
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 26 Jun 2005 12:19:27 +0000 (12:19 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Sun, 26 Jun 2005 12:19:27 +0000 (12:19 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@865 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-appserver/NGObjWeb/ChangeLog
sope-appserver/NGObjWeb/Version
sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAV.h
sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAV.m
sope-appserver/NGObjWeb/WebDAV/SoObjectWebDAVDispatcher.m
sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m

index b4586d9e9329610c6e351c0d1b73b0660bdfce90..19247a24307aad84afc61aba3e48432044e4020d 100644 (file)
@@ -1,3 +1,21 @@
+2005-06-26  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.5.167
+       
+       * WebDAV/SoWebDAVRenderer.m: improved reliability by checking the class
+         of OPTIONS method results, deprecated array results
+       
+       * WebDAV/SoObjectWebDAVDispatcher.m: when receiving an OPTIONS request,
+         the dispatcher will try to invoke a method with the same name on the
+         object. If none is available, the dispatcher checks supported methods
+         and DAV compliance classes
+       
+       * WebDAV/SoObject+SoDAV.m: added method to determine the WebDAV
+         compliance classes supported by an object
+         (davComplianceClassesInContext:). The method now only returns class 2
+         if the object returns a lock manager object. Also moved the 'allowed'
+         processing to the object (-davAllowedMethodsInContext: method)
+
 2005-06-24  Helge Hess  <helge.hess@opengroupware.org>
 
        * SoObjects/SoProductRegistry.m: fixed product lookup on MacOSX with
index f1dd79df97d289f9da1c775b1134a3482267cafb..ad9ca6c9636cc20a552ad26dd29735699060ec73 100644 (file)
@@ -1,6 +1,6 @@
 # version file
 
-SUBMINOR_VERSION:=166
+SUBMINOR_VERSION:=167
 
 # v4.5.122 requires libNGExtensions v4.5.153
 # v4.5.91  requires libNGExtensions v4.5.134
index 5f7504f908183de7e04baf52b03c09b201db5c76..98ef19220424495d9208f42ec7f35a80a865cae8 100644 (file)
@@ -49,6 +49,8 @@
 - (NSArray *)davQueryOnSelf:(EOFetchSpecification *)_fs inContext:(id)_ctx;
 
 - (NSArray *)defaultWebDAVPropertyNamesInContext:(id)_ctx;
+- (NSArray *)davComplianceClassesInContext:(id)_ctx;
+- (NSArray *)davAllowedMethodsInContext:(id)_ctx;
 
 /*
   Editing the object properties (PROPPATCH)
index 4c663685ef58f6d109fcc7ef0908540ea142dd3f..38ee46b8874e4add74be1a1ad84f83a972574a17 100644 (file)
   return defNames;
 }
 
+- (NSArray *)davComplianceClassesInContext:(id)_ctx {
+  /*
+    Class 1 is everything in WebDAV which is a MUST.
+    
+    Class 2 adds the LOCK method, the supportedlock property, the lockdiscovery
+    property, the time-out response header and the lock-token request header.
+    
+    In this method we check that by querying the lock manager. If the object
+    has one, it will return class 2, otherwise just class 1.
+  */
+  static NSArray *class1 = nil, *class2 = nil;
+  
+  if (class1 == nil)
+    class1 = [[NSArray alloc] initWithObjects:@"1", nil];
+  if (class2 == nil)
+    class2 = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
+  
+  return ([self davLockManagerInContext:_ctx] != nil)
+    ? class2 : class1;
+}
+
+- (NSArray *)davAllowedMethodsInContext:(id)_ctx {
+  static NSArray *defMethods = nil;
+  NSMutableArray *allow;
+  
+  if (defMethods == nil) {
+    defMethods = [[[NSUserDefaults standardUserDefaults] 
+                                   arrayForKey:@"SoWebDAVDefaultAllowMethods"] 
+                                   copy];
+  }
+  
+  allow = [NSMutableArray arrayWithCapacity:16];
+  if (defMethods) [allow addObjectsFromArray:defMethods];
+  
+  if ([self respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
+    [allow addObject:@"PROPFIND"];
+    [allow addObject:@"SEARCH"];
+  }
+  if ([self respondsToSelector:
+             @selector(davSetProperties:removePropertiesNamed:)])
+    [allow addObject:@"PROPPATCH"];
+  
+  return allow;
+}
+
 /* attributes */
 
 - (BOOL)davIsCollection {
   ctx = [[WOApplication application] context];
   i = 0;
   e = [self davChildKeysInContext:ctx];
-  while ((childName = [e nextObject])) {
-    if (![[self lookupName:childName inContext:ctx acquire:NO] davIsCollection])
+  while ((childName = [e nextObject]) != nil) {
+    if (![[self lookupName:childName inContext:ctx acquire:NO]davIsCollection])
       i++;
   }
   return i;
index 1d716a3663c9be055ba398880c1c1c5846bcb696..80c157f5c57c02e9a2298b73788f7d35e0bdb24f 100644 (file)
@@ -105,31 +105,6 @@ static NSTimeZone                *gmt      = nil;
                      userInfo:ui];
 }
 
-- (NSArray *)allowedMethods {
-  static NSArray *defMethods = nil;
-  NSMutableArray *allow;
-
-  if (defMethods == nil) {
-    defMethods = [[[NSUserDefaults standardUserDefaults] 
-                                   arrayForKey:@"SoWebDAVDefaultAllowMethods"] 
-                                   copy];
-  }
-  
-  allow = [NSMutableArray arrayWithCapacity:16];
-  if (defMethods) [allow addObjectsFromArray:defMethods];
-  
-  if ([self->object 
-           respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
-    [allow addObject:@"PROPFIND"];
-    [allow addObject:@"SEARCH"];
-  }
-  if ([self->object respondsToSelector:
-            @selector(davSetProperties:removePropertiesNamed:)])
-    [allow addObject:@"PROPPATCH"];
-  
-  return allow;
-}
-
 - (NSString *)baseURLForContext:(WOContext *)_ctx {
   /*
     Note: Evolution doesn't correctly transfer the "Host:" header, it
@@ -175,16 +150,38 @@ static NSTimeZone                *gmt      = nil;
 
 /* core HTTP methods */
 
-- (id)doGET:(WOContext *)_ctx {
+- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx {
+  /* returns 'nil' if the object had no such method */
   NSException *e;
   id methodObject;
+  id result;
   
+  methodObject =
+    [self->object lookupName:_method inContext:_ctx acquire:NO];
+  if (![methodObject isNotNull])
+    return nil;
+  if ([methodObject isKindOfClass:[NSException class]])
+    return methodObject;
+  if ((e = [self->object validateName:_method inContext:_ctx]) != nil)
+    return e;
   
-  if ((methodObject = 
-       [self->object lookupName:@"GET" inContext:_ctx acquire:NO]) == nil)
+  if ([methodObject respondsToSelector:
+                     @selector(takeValuesFromRequest:inContext:)])
+    [methodObject takeValuesFromRequest:[_ctx request] inContext:_ctx];
+  
+  result = [methodObject callOnObject:self->object inContext:_ctx];
+  return (result != nil) ? result : [NSNull null];
+}
+
+- (id)doGET:(WOContext *)_ctx {
+  NSException *e;
+  id methodObject;
+  
+  methodObject = [self->object lookupName:@"GET" inContext:_ctx acquire:NO];
+  if (methodObject == nil)
     methodObject = [self->object lookupDefaultMethod];
   else {
-    if ((e = [self->object validateName:@"GET" inContext:_ctx]))
+    if ((e = [self->object validateName:@"GET" inContext:_ctx]) != nil)
       return e;
   }
   
@@ -269,7 +266,23 @@ static NSTimeZone                *gmt      = nil;
 }
 
 - (id)doOPTIONS:(WOContext *)_ctx {
-  return [self allowedMethods];
+  WOResponse *response;
+  NSArray    *tmp;
+  id         result;
+  
+  if ((result = [self _callObjectMethod:@"OPTIONS" inContext:_ctx]) != nil)
+    return result;
+  
+  response = [_ctx response];
+  [response setStatus:200 /* OK */];
+  
+  if ((tmp = [self->object davAllowedMethodsInContext:_ctx]) != nil) 
+    [response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"allow"];
+  
+  if ((tmp = [self->object davComplianceClassesInContext:_ctx]) != nil) 
+    [response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"dav"];
+  
+  return response;
 }
 
 - (id)doHEAD:(WOContext *)_ctx {
index c053f4994f9fd0abea3a08104f32b71b3ddb3955..c4490572486ffd27ab9eaaffae574d803ed80db2 100644 (file)
@@ -889,12 +889,23 @@ static BOOL         formatOutput = NO;
 }
 
 - (BOOL)renderOptions:(id)_object inContext:(WOContext *)_ctx {
-  WOResponse *r = [_ctx response];
+  WOResponse *r;
   
-  [r setStatus:200];
+  r = [_ctx response];
+  [r setStatus:200 /* OK */];
   [r setHeader:@"1,2" forKey:@"DAV"]; // TODO: select protocol level
   //[r setHeader:@"" forKey:@"Etag"]; 
-  [r setHeader:[_object componentsJoinedByString:@", "] forKey:@"allow"];
+  
+  if (![_object isNotNull])
+    ;
+  else if ([_object isKindOfClass:[NSArray class]]) {
+    /* DEPRECATED */
+    [r setHeader:[_object componentsJoinedByString:@", "] forKey:@"allow"];
+  }
+  else {
+    [self logWithFormat:@"ERROR: unexpected options result: %@ (class=%@)", 
+           _object, [_object class]];
+  }
   return YES;
 }