Monotone-Parent: 1ffb41682368b46b7d5dfbe50eb430e0859f6837

Monotone-Revision: 9402acf99e73ef8bdcad7719c88dc1d6a3ee27d4

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2008-07-09T15:42:22
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2008-07-09 15:42:22 +00:00
parent fb79b7a0c1
commit 5886e82c79
3 changed files with 100 additions and 81 deletions
+9
View File
@@ -1,3 +1,12 @@
2008-07-09 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject
-PUTAction:_ctx]): the version passed to
saveContentString:baseVersion: is the current value of "version".
If the operation is succesful, the version is incremented from
here since no refresh is done from GCS. The returned etag has thus
now the correct value.
2008-07-08 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/Appointments/SOGoAppointmentFolder.m
+2 -2
View File
@@ -45,8 +45,8 @@
andContent: (NSString *) newContent
inContainer: (SOGoGCSFolder *) newContainer;
- (id) initWithRecord: (NSDictionary *) objectRecord
inContainer: (id) newContainer;
+ (id) initWithName: (NSString *) newName
inContainer: (SOGoGCSFolder *) newContainer;
- (id) initWithName: (NSString *) newName
andContent: (NSString *) newContent
inContainer: (SOGoGCSFolder *) newContainer;
+89 -79
View File
@@ -53,13 +53,13 @@
return newObject;
}
+ (id) objectWithName: (NSDictionary *) objectRecord
+ (id) objectWithName: (NSString *) newName
andContent: (NSString *) newContent
inContainer: (SOGoGCSFolder *) newContainer
{
SOGoContentObject *newObject;
newObject = [[self alloc] initWithName: objectRecord
newObject = [[self alloc] initWithName: newName
andContent: newContent
inContainer: newContainer];
[newObject autorelease];
@@ -104,7 +104,7 @@
}
- (id) initWithRecord: (NSDictionary *) objectRecord
inContainer: (id) newContainer
inContainer: (SOGoGCSFolder *) newContainer
{
NSString *newName;
@@ -119,7 +119,7 @@
- (id) initWithName: (NSString *) newName
andContent: (NSString *) newContent
inContainer: (id) newContainer
inContainer: (SOGoGCSFolder *) newContainer
{
if ((self = [self initWithName: newName inContainer: newContainer]))
{
@@ -233,88 +233,98 @@
- (id) PUTAction: (WOContext *) _ctx
{
WORequest *rq;
NSException *error;
WORequest *rq;
NSException *error;
unsigned int baseVersion;
id etag, tmp;
BOOL needsLocation;
if ((error = [self matchesRequestConditionInContext:_ctx]) != nil)
return error;
rq = [_ctx request];
/* check whether its a request to the 'special' 'new' location */
/*
Note: this is kinda hack. The OGo ZideStore detects writes to 'new' as
object creations and will assign a server side identifier. Most
current GroupDAV clients rely on this behaviour, so we reproduce it
here.
A correct client would loop until it has a name which doesn't not
yet exist (by using if-none-match).
*/
needsLocation = NO;
tmp = [[self nameInContainer] stringByDeletingPathExtension];
if ([tmp isEqualToString:@"new"]) {
tmp = [self globallyUniqueObjectId];
needsLocation = YES;
[self debugWithFormat:
@"reassigned a new location for special new-location: %@", tmp];
/* kinda dangerous */
ASSIGNCOPY(nameInContainer, tmp);
}
/* 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)
*/
tmp = [rq headerForKey:@"if-match"];
tmp = [self parseETagList:tmp];
etag = nil;
if ([tmp count] > 0) {
if ([tmp 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: %@", tmp];
}
etag = [tmp objectAtIndex:0];
}
baseVersion = ([etag length] > 0)
? [etag unsignedIntValue]
: 0 /* 0 means 'do not check' */;
/* attempt a save */
id etag, tmp;
BOOL needsLocation;
WOResponse *response;
if ((error = [self saveContentString: [rq contentAsString]
baseVersion: baseVersion]) != nil)
return error;
error = [self matchesRequestConditionInContext: _ctx];
if (error)
response = (WOResponse *) error;
else
{
rq = [_ctx request];
/* setup response */
/* check whether its a request to the 'special' 'new' location */
/*
Note: this is kinda hack. The OGo ZideStore detects writes to 'new' as
object creations and will assign a server side identifier. Most
current GroupDAV clients rely on this behaviour, so we reproduce it
here.
A correct client would loop until it has a name which doesn't not
yet exist (by using if-none-match).
*/
needsLocation = NO;
tmp = [[self nameInContainer] stringByDeletingPathExtension];
if ([tmp isEqualToString: @"new"])
{
tmp = [self globallyUniqueObjectId];
needsLocation = YES;
[self debugWithFormat:
@"reassigned a new location for special new-location: %@", tmp];
/* kinda dangerous */
ASSIGNCOPY (nameInContainer, tmp);
}
// TODO: this should be automatic in the SoDispatcher if we return nil?
[[_ctx response] setStatus: 201 /* Created */];
/* 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)
*/
tmp = [rq headerForKey: @"if-match"];
tmp = [self parseETagList: tmp];
etag = nil;
if ([tmp count] > 0) {
if ([tmp 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: %@", tmp];
}
etag = [tmp objectAtIndex: 0];
}
baseVersion = (isNew ? 0 : version);
if ((etag = [self davEntityTag]) != nil)
[[_ctx response] setHeader:etag forKey:@"etag"];
/* attempt a save */
error = [self saveContentString: [rq contentAsString]
baseVersion: baseVersion];
if (error)
response = (WOResponse *) error;
else
{
version++;
response = [_ctx response];
/* setup response */
if (needsLocation) {
[[_ctx response] setHeader:[self baseURLInContext:_ctx]
forKey:@"location"];
}
// TODO: this should be automatic in the SoDispatcher if we return nil?
[response setStatus: 201 /* Created */];
return [_ctx response];
etag = [self davEntityTag];
if (etag)
{
[response setHeader: etag forKey: @"etag"];
if (needsLocation)
[response setHeader: [self baseURLInContext:_ctx]
forKey: @"location"];
}
}
}
return response;
}
/* E-Tags */