]> err.no Git - scalable-opengroupware.org/commitdiff
added etag processing
authorhelge <helge@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Thu, 14 Jul 2005 08:25:55 +0000 (08:25 +0000)
committerhelge <helge@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Thu, 14 Jul 2005 08:25:55 +0000 (08:25 +0000)
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@742 d1b88da0-ebda-0310-925b-ed51d893ca5b

SOGo/SoObjects/SOGo/ChangeLog
SOGo/SoObjects/SOGo/SOGoContentObject.h
SOGo/SoObjects/SOGo/SOGoContentObject.m
SOGo/SoObjects/SOGo/Version

index 53e9726afd9c7d085a1303172309f0690e432c28..25d2d2b577573edf152eeffb85e84bab711c7d82 100644 (file)
@@ -1,3 +1,9 @@
+2005-07-14  Helge Hess  <helge.hess@opengroupware.org>
+
+       * SOGoContentObject.m: added transactionally save etag-checks in PUT
+         (use the etag value as the baseVersion in the content store)
+         (v0.9.53)
+
 2005-07-13  Helge Hess  <helge.hess@opengroupware.org>
 
        * v0.9.52
index 5c2443d1e090cdb317e11a20f7fce56a6b1ee82f..1567063ba92018fc61d77a3e8ba2a32f02277f2d 100644 (file)
@@ -46,6 +46,8 @@
 /* content */
 
 - (NSString *)contentAsString;
+- (NSException *)saveContentString:(NSString *)_str
+  baseVersion:(unsigned int)_baseVersion;
 - (NSException *)saveContentString:(NSString *)_str;
 - (NSException *)delete;
 
index e942dc4facd911d08fe6bf9643bf37d4900b131e..a520050c46d1b51b779de35de13a86680ad89645 100644 (file)
 #include "common.h"
 #include <GDLContentStore/GCSFolder.h>
 
+@interface SOGoContentObject(ETag)
+- (NSArray *)parseETagList:(NSString *)_c;
+@end
+
 @implementation SOGoContentObject
 
 static BOOL kontactGroupDAV = YES;
@@ -108,7 +112,9 @@ static BOOL kontactGroupDAV = YES;
   return self->content;
 }
 
-- (NSException *)saveContentString:(NSString *)_str {
+- (NSException *)saveContentString:(NSString *)_str
+  baseVersion:(unsigned int)_baseVersion
+{
   /* Note: "iCal multifolder saves" are implemented in the apt subclass! */
   GCSFolder   *folder;
   NSException *ex;
@@ -117,12 +123,18 @@ static BOOL kontactGroupDAV = YES;
     [self errorWithFormat:@"Did not find folder of content object."];
     return nil;
   }
-  if ((ex = [folder writeContent:_str toName:[self nameInContainer]])) {
+  
+  ex = [folder writeContent:_str toName:[self nameInContainer]
+              baseVersion:_baseVersion];
+  if (ex != nil) {
     [self errorWithFormat:@"write failed: %@", ex];
     return ex;
   }
   return nil;
 }
+- (NSException *)saveContentString:(NSString *)_str {
+  return [self saveContentString:_str baseVersion:0 /* don't check */];
+}
 
 - (NSException *)delete {
   /* Note: "iCal multifolder saves" are implemented in the apt subclass! */
@@ -146,15 +158,48 @@ static BOOL kontactGroupDAV = YES;
 /* actions */
 
 - (id)PUTAction:(WOContext *)_ctx {
-  WORequest   *rq;
-  NSException *error;
-  id etag;
+  WORequest    *rq;
+  NSException  *error;
+  unsigned int baseVersion;
+  id           etag;
   
   if ((error = [self matchesRequestConditionInContext:_ctx]) != nil)
     return error;
   
   rq = [_ctx request];
-  if ((error = [self saveContentString:[rq contentAsString]]) != nil)
+  
+  /* determine base version from etag in if-match header */
+  /*
+    Note: The -matchesRequestConditionInContext: already checks whether the
+          etag matches and returns an HTTP exception in case it doesn't.
+         We retrieve the etag again here to _ensure_ a transactionally save
+         commit.
+          (between the check and the update a change could have been done)
+  */
+  etag = [rq headerForKey:@"if-match"];
+  etag = [self parseETagList:etag];
+  if ([etag count] > 0) {
+    if ([etag count] > 1) {
+      /*
+       Note: we would have to attempt a save for _each_ of the etags being
+             passed in! In practice most WebDAV clients submit exactly one
+             etag.
+      */
+      [self warnWithFormat:
+             @"Got multiple if-match etags from client, only attempting to "
+             @"save with the first: %@", etag];
+    }
+    
+    etag = [etag objectAtIndex:0];
+  }
+  baseVersion = ([etag length] > 0)
+    ? [etag unsignedIntValue]
+    : 0 /* 0 means 'do not check' */;
+  
+  /* attempt a save */
+  
+  if ((error = [self saveContentString:[rq contentAsString]
+                    baseVersion:baseVersion]) != nil)
     return error;
   
   // TODO: this should be automatic if we return nil?
index 1a25ad08848acb5a7596f41cb81648cd53f30fd7..53f7a36009aa38908fc99d587ab1b6e1a4f35cf8 100644 (file)
@@ -1,6 +1,6 @@
 # version file
 
-SUBMINOR_VERSION:=52
+SUBMINOR_VERSION:=53
 
 # v0.9.50 requires libGDLContentStore v4.5.30
 # v0.9.34 requires libGDLContentStore v4.5.26