From ab8e3d7659e153df1e587d525decf20997cf5a4b Mon Sep 17 00:00:00 2001 From: helge Date: Thu, 4 May 2006 22:19:42 +0000 Subject: [PATCH] Improved WebDAV support. git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1261 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-appserver/NGObjWeb/ChangeLog | 12 ++ .../SoObjects/SoObjectRequestHandler.m | 12 +- sope-appserver/NGObjWeb/Version | 2 +- .../NGObjWeb/WEClientCapabilities.m | 10 + .../NGObjWeb/WebDAV/SoWebDAVRenderer.m | 195 +++++++++++------- 5 files changed, 156 insertions(+), 75 deletions(-) diff --git a/sope-appserver/NGObjWeb/ChangeLog b/sope-appserver/NGObjWeb/ChangeLog index 4a5399fc..131e0d72 100644 --- a/sope-appserver/NGObjWeb/ChangeLog +++ b/sope-appserver/NGObjWeb/ChangeLog @@ -1,3 +1,15 @@ +2006-05-05 Helge Hess + + * v4.5.231 + + * WebDAV/SoWebDAVRenderer.m: major change: WebDAV properties which got + NSNull as their value are now rendered in a 404-propstat element. So + if you want to have empty properties delivered, return empty strings. + + * SoObjects/SoObjectRequestHandler.m: minor code cleanups + + * WEClientCapabilities.m: added support for Office 2003 + 2006-05-04 Helge Hess * v4.5.230 diff --git a/sope-appserver/NGObjWeb/SoObjects/SoObjectRequestHandler.m b/sope-appserver/NGObjWeb/SoObjects/SoObjectRequestHandler.m index 38a4d35c..6aa2d000 100644 --- a/sope-appserver/NGObjWeb/SoObjects/SoObjectRequestHandler.m +++ b/sope-appserver/NGObjWeb/SoObjects/SoObjectRequestHandler.m @@ -227,10 +227,12 @@ static NSString *redirectURISafetySuffix = nil; unsigned i, count; NSString *m; NSArray *a; - + if (rqKeys == nil) /* cache set of registered request handlers */ rqKeys = [[[WOApplication application] registeredRequestHandlerKeys] copy]; + + /* check request handler keys */ m = [_rq requestHandlerKey]; if ([rqKeys containsObject:m]) { @@ -285,7 +287,7 @@ static NSString *redirectURISafetySuffix = nil; if ([self enableZideLookHack]) p = [self hackZideLookName:p]; - if ([p length] > 0) + if ([p isNotEmpty]) [traversalPath addObject:p]; } @@ -332,7 +334,7 @@ static NSString *redirectURISafetySuffix = nil; /* build traversal path */ traversalPath = [self traversalPathFromRequest:_rq]; - if (traversalPath) + if (traversalPath != nil) [_ctx setSoRequestTraversalPath:traversalPath]; /* setup root object */ @@ -496,8 +498,8 @@ static NSString *redirectURISafetySuffix = nil; { /* split up this big method */ WOResponse *r; - id object; - id authenticator; + id object; + id authenticator; BOOL doDispatch; if (debugLogger) { diff --git a/sope-appserver/NGObjWeb/Version b/sope-appserver/NGObjWeb/Version index 65af81b9..704a3bc2 100644 --- a/sope-appserver/NGObjWeb/Version +++ b/sope-appserver/NGObjWeb/Version @@ -1,6 +1,6 @@ # version file -SUBMINOR_VERSION:=230 +SUBMINOR_VERSION:=231 # v4.5.214 requires libNGExtensions v4.5.179 # v4.5.122 requires libNGExtensions v4.5.153 diff --git a/sope-appserver/NGObjWeb/WEClientCapabilities.m b/sope-appserver/NGObjWeb/WEClientCapabilities.m index ccf2b97c..99a50878 100644 --- a/sope-appserver/NGObjWeb/WEClientCapabilities.m +++ b/sope-appserver/NGObjWeb/WEClientCapabilities.m @@ -310,6 +310,10 @@ /* WebFolder */ self->browser = WEUA_WebFolder; } + else if (strstr(ua, "Microsoft Office Protocol Discovery")) { + /* Word 2003, treat as WebFolder */ + self->browser = WEUA_WebFolder; + } else if (strstr(ua, "curl")) { /* curl program */ self->browser = WEUA_CURL; @@ -960,6 +964,9 @@ static NSString *WEClientDetectorFormName = @"WEClientDetect"; MacOSX 10.2.1 DAV FS WebDAVFS/1.2.1 (01218000) Darwin/6.1 (Power Macintosh) + + MacOSX 10.4.2 DAV FS + WebDAVFS/1.4.1 (01418000) Darwin/8.6.0 (Power Macintosh) Cadaver 0.17.0 'cadaver/0.17.0 neon/0.12.0-dev' @@ -1064,4 +1071,7 @@ static NSString *WEClientDetectorFormName = @"WEClientDetect"; WebFolders Win XP SP2 'Microsoft-WebDAV-MiniRedir/5.1.2600' + + Word 2003 + 'Microsoft Office Protocol Discovery' */ diff --git a/sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m b/sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m index c4490572..9c5c5c13 100644 --- a/sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m +++ b/sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m @@ -1,5 +1,6 @@ /* - Copyright (C) 2000-2005 SKYRIX Software AG + Copyright (C) 2000-2006 SKYRIX Software AG + Copyright (C) 2006 Helge Hess This file is part of SOPE. @@ -497,6 +498,61 @@ static BOOL formatOutput = NO; return stat; } +- (void)renderNullProperty:(NSString *)_key + toResponse:(WOResponse *)r inContext:(WOContext *)_ctx + namesOnly:(BOOL)_namesOnly isBrief:(BOOL)isBrief + tagToPrefix:(NSDictionary *)extNameCache + nsToPrefix:(NSDictionary *)nsToPrefix +{ + NSString *extName; + + extName = [extNameCache objectForKey:_key]; + + [r appendContentCharacter:'<']; + [r appendContentString:extName]; + [r appendContentString:@"/>"]; + if (formatOutput) [r appendContentCharacter:'\n']; +} + +- (void)renderProperty:(NSString *)_key value:(id)value + toResponse:(WOResponse *)r inContext:(WOContext *)_ctx + namesOnly:(BOOL)_namesOnly + tagToPrefix:(NSDictionary *)extNameCache + nsToPrefix:(NSDictionary *)nsToPrefix +{ + NSString *extName; + NSString *s; + + extName = [extNameCache objectForKey:_key]; + + if (_namesOnly) { + [r appendContentCharacter:'<']; + [r appendContentString:extName]; + [r appendContentString:@"/>"]; + if (formatOutput) [r appendContentCharacter:'\n']; + return; + } + + if ([value isKindOfClass:[SoWebDAVValue class]]) { + s = [value stringForTag:_key rawName:extName + inContext:_ctx prefixes:nsToPrefix]; + [r appendContentString:s]; + } + else { + [r appendContentCharacter:'<']; + [r appendContentString:extName]; + [r appendContentCharacter:'>']; + + s = [self stringForValue:value ofProperty:_key prefixes:nsToPrefix]; + [r appendContentString:s]; + + [r appendContentString:@""]; + if (formatOutput) [r appendContentCharacter:'\n']; + } +} + - (void)renderSearchResultEntry:(id)entry inContext:(WOContext *)_ctx namesOnly:(BOOL)_namesOnly attributes:(NSArray *)_attrs @@ -507,6 +563,7 @@ static BOOL formatOutput = NO; { /* Note: the entry is an NSArray in case _namesOnly is requested! */ // TODO: use -valueForKey: to improve NSNull handling ? + NSMutableArray *missingProps; WOResponse *r; NSEnumerator *keys; NSString *key; @@ -539,6 +596,12 @@ static BOOL formatOutput = NO; [self warnWithFormat:@"no key for {DAV:}href in property map !"]; } } + /* + TODO: where is this used? It doesn't make a lot of sense since one + response can have multiple status values?! One for each + property. + So: do we actually use this special key anywhere? + */ if ((stat = [entry valueForKey:@"{DAV:}status"]) == nil) { if ((key = [_propMap objectForKey:@"{DAV:}status"])) stat = [entry valueForKey:key]; @@ -560,11 +623,14 @@ static BOOL formatOutput = NO; [self debugWithFormat:@" href: %@", href]; } - /* generate */ + /* start the response */ + [r appendContentString:@""]; if (formatOutput) [r appendContentCharacter:'\n']; + + /* write the href the response is for */ - if ([href isNotNull]) { + if ([href isNotEmpty]) { [r appendContentString:@""]; /* TODO: need to find out what is appropriate! While Cadaver and ZideLook @@ -587,90 +653,81 @@ static BOOL formatOutput = NO; } [r appendContentString:@""]; + + if (stat != nil) { + [r appendContentString:@""]; + [r appendContentXMLString:[stat stringValue]]; + [r appendContentString:@""]; + } + [r appendContentString:@""]; if (formatOutput) [r appendContentCharacter:'\n']; - /* now the properties */ - + /* first the available properties */ + + missingProps = nil; keys = [_attrs objectEnumerator] ; - while ((key = [keys nextObject])) { - NSString *extName; + while ((key = [keys nextObject]) != nil) { NSString *okey; id value; + + /* determine value */ -#if 0 /* this filter probably doesn't make sense ? */ - /* filter out predefined props */ - if ([key isEqualToString:@"{DAV:}href"]) continue; - if ([key isEqualToString:@"{DAV:}status"]) continue; -#endif - - extName = [extNameCache objectForKey:key]; - - if (_namesOnly) { - [r appendContentCharacter:'<']; - [r appendContentString:extName]; - [r appendContentString:@"/>"]; - if (formatOutput) [r appendContentCharacter:'\n']; - continue; - } - - // TODO: we should support property status (eg encode 404 on NSNull) - if ((okey = [_propMap objectForKey:key]) == nil) okey = key; - - if ([key isEqualToString:@"{DAV:}href"]) - value = href; - else - value = [entry valueForKey:okey]; - if ([value isNotNull]) { - NSString *s; - - if ([value isKindOfClass:[SoWebDAVValue class]]) { - s = [value stringForTag:key rawName:extName - inContext:_ctx prefixes:nsToPrefix]; - [r appendContentString:s]; - } - else { - [r appendContentCharacter:'<']; - [r appendContentString:extName]; - [r appendContentCharacter:'>']; - - s = [self stringForValue:value ofProperty:key prefixes:nsToPrefix]; - [r appendContentString:s]; - - [r appendContentString:@""]; - if (formatOutput) [r appendContentCharacter:'\n']; - } + value = [key isEqualToString:@"{DAV:}href"] + ? href + : [entry valueForKey:okey]; + + if (![value isNotNull]) { + if (missingProps == nil) + missingProps = [[NSMutableArray alloc] initWithCapacity:8]; + [missingProps addObject:key]; continue; } - if (!isBrief) { - /* - Not sure whether this is correct, do we need to encode null attrs? - Seems like Evo gets confused on that. - TODO: probably add a 404 property status for that! - */ - [r appendContentCharacter:'<']; - [r appendContentString:extName]; - [r appendContentString:@"/>"]; - if (formatOutput) [r appendContentCharacter:'\n']; + /* render */ + + [self renderProperty:key value:value + toResponse:r inContext:_ctx + namesOnly:_namesOnly + tagToPrefix:extNameCache nsToPrefix:nsToPrefix]; + } + + /* next the missing properties unless we are brief */ + + if (!isBrief && [missingProps isNotEmpty]) { + /* close previous propstat and open a new one */ + [r appendContentString:@""]; + if (formatOutput) [r appendContentCharacter:'\n']; + + [r appendContentString:@""]; + [r appendContentString: + @"HTTP/1.1 404 Resource Not Found"]; + [r appendContentString:@""]; + if (formatOutput) [r appendContentCharacter:'\n']; + + keys = [missingProps objectEnumerator] ; + while ((key = [keys nextObject]) != nil) { + [self renderNullProperty:key + toResponse:r inContext:_ctx + namesOnly:_namesOnly isBrief:isBrief + tagToPrefix:extNameCache nsToPrefix:nsToPrefix]; } } - + + [missingProps release]; missingProps = nil; + [r appendContentString:@""]; if (formatOutput) [r appendContentCharacter:'\n']; - if (stat != nil) { - [r appendContentString:@""]; - [r appendContentXMLString:[stat stringValue]]; - [r appendContentString:@""]; - } + [r appendContentString:@""]; - [r appendContentString:@""]; + + /* finish response */ + + [r appendContentString:@""]; if (formatOutput) [r appendContentCharacter:'\n']; } @@ -796,7 +853,7 @@ static BOOL formatOutput = NO; [self debugWithFormat:@" baseURL: %@", baseURL]; entryCount = 0; /* Note: this will clash with streamed output later */ - while ((entry = [_entries nextObject])) { + while ((entry = [_entries nextObject]) != nil) { [self renderSearchResultEntry:entry inContext:_ctx namesOnly:_namesOnly attributes:_attrs propertyMap:_propMap baseURL:baseURL tagToPrefix:extNameCache nsToPrefix:nsToPrefix]; -- 2.39.5