From c532432d567bd2cb1dabc43349eeb4d3de6706c2 Mon Sep 17 00:00:00 2001 From: helge Date: Thu, 14 Jul 2005 08:25:55 +0000 Subject: [PATCH] added etag processing git-svn-id: http://svn.opengroupware.org/SOGo/trunk@742 d1b88da0-ebda-0310-925b-ed51d893ca5b --- SOGo/SoObjects/SOGo/ChangeLog | 6 +++ SOGo/SoObjects/SOGo/SOGoContentObject.h | 2 + SOGo/SoObjects/SOGo/SOGoContentObject.m | 57 ++++++++++++++++++++++--- SOGo/SoObjects/SOGo/Version | 2 +- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/SOGo/SoObjects/SOGo/ChangeLog b/SOGo/SoObjects/SOGo/ChangeLog index 53e9726a..25d2d2b5 100644 --- a/SOGo/SoObjects/SOGo/ChangeLog +++ b/SOGo/SoObjects/SOGo/ChangeLog @@ -1,3 +1,9 @@ +2005-07-14 Helge Hess + + * 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 * v0.9.52 diff --git a/SOGo/SoObjects/SOGo/SOGoContentObject.h b/SOGo/SoObjects/SOGo/SOGoContentObject.h index 5c2443d1..1567063b 100644 --- a/SOGo/SoObjects/SOGo/SOGoContentObject.h +++ b/SOGo/SoObjects/SOGo/SOGoContentObject.h @@ -46,6 +46,8 @@ /* content */ - (NSString *)contentAsString; +- (NSException *)saveContentString:(NSString *)_str + baseVersion:(unsigned int)_baseVersion; - (NSException *)saveContentString:(NSString *)_str; - (NSException *)delete; diff --git a/SOGo/SoObjects/SOGo/SOGoContentObject.m b/SOGo/SoObjects/SOGo/SOGoContentObject.m index e942dc4f..a520050c 100644 --- a/SOGo/SoObjects/SOGo/SOGoContentObject.m +++ b/SOGo/SoObjects/SOGo/SOGoContentObject.m @@ -24,6 +24,10 @@ #include "common.h" #include +@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? diff --git a/SOGo/SoObjects/SOGo/Version b/SOGo/SoObjects/SOGo/Version index 1a25ad08..53f7a360 100644 --- a/SOGo/SoObjects/SOGo/Version +++ b/SOGo/SoObjects/SOGo/Version @@ -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 -- 2.39.5