/*
TODO: is it required by SOAP that the HTTP method is POST?
+ Note:
+ Servers also set a SOAPAction HTTP header.
+
SOAP sample:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope
</loginRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
+
+ Another (http://novell.com/simias/domain/GetDomainID):
+ <?xml version="1.0" encoding="utf-8"?>
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <soap:Body>
+ <GetDomainID xmlns="http://novell.com/simias/domain" />
+ </soap:Body>
+ </soap:Envelope>
*/
@interface SoSOAPRenderer : SoDefaultRenderer
debugOn = [ud boolForKey:@"SoObjectSOAPDispatcherDebugEnabled"];
if (debugOn) NSLog(@"Note: SOPE SOAP dispatcher debugging turned on.");
+
+ debugParsing = [ud boolForKey:@"SoObjectSOAPDispatcherParserDebugEnabled"];
+ if (debugParsing) NSLog(@"Note: SOPE SOAP parsing debugging turned on.");
}
/* XML actions */
[self debugWithFormat:@" setting client object: %@", clientObject];
[_ctx setClientObject:clientObject];
}
-
+
/* find callable (method) object */
// TODO: should we allow acquisition?
methodObject = [clientObject lookupName:_actionName inContext:_ctx
acquire:NO];
if (methodObject == nil) {
- if ([_actionName hasSuffix:@"Request"])
- _actionName = [_actionName substringToIndex:[_actionName length] - 7];
- methodObject = [clientObject lookupName:_actionName inContext:_ctx
- acquire:NO];
+ /* check for common names like "GetFolderRequest" => "GetFolder" */
+ if ([_actionName hasSuffix:@"Request"]) {
+ NSString *an;
+
+ an = [_actionName substringToIndex:([_actionName length] - 7)];
+ if (debugOn) [self debugWithFormat:@" try special name: %@", an];
+ methodObject = [clientObject lookupName:an inContext:_ctx acquire:NO];
+ if (methodObject != nil) _actionName = an;
+ }
+ }
+ if (methodObject == nil) {
+ /* check for names like "http://novell.com/domain/GetID" => "GetID" */
+ NSRange r;
+
+ r = [_actionName rangeOfString:@"/" options:NSBackwardsSearch];
+ if (r.length > 0) {
+ NSString *an;
+
+ an = [_actionName substringFromIndex:(r.location + r.length)];
+ if (debugOn) [self debugWithFormat:@" try special name: %@", an];
+
+ methodObject = [clientObject lookupName:an inContext:_ctx acquire:NO];
+ if (methodObject != nil) _actionName = an;
+ }
}
if (methodObject == nil) {
/*
Note: the SOAPAction is also contained in the body which is probably
- considered the authority.
+ considered the authority? We currently prefer the header when
+ available.
*/
-
SOAPAction = [rq headerForKey:@"soapaction"];
- if ([SOAPAction length] == 0) {
+ if ([SOAPAction length] > 1) {
+
+ if ([SOAPAction characterAtIndex:0] == '"' &&
+ [SOAPAction characterAtIndex:([SOAPAction length] - 1)] == '"') {
+ /* a quoted header, like "http://novell.com/simias/domain/GetDomainID" */
+ NSRange r;
+
+ r.location = 1;
+ r.length = [SOAPAction length] - 2;
+ SOAPAction = [SOAPAction substringWithRange:r];
+ }
+ }
+ if (![SOAPAction isNotEmpty]) {
[self errorWithFormat:@"missing SOAPAction HTTP header!"];
return nil;
}
-
+
/* parse XML */
if ((dom = [rq contentAsDOMDocument]) == nil) {
static BOOL debugOn = NO;
+ (void)initialize {
+ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
static BOOL didInit = NO;
if (didInit) return;
didInit = YES;
+
+ debugOn = [ud boolForKey:@"SoSelectorInvocationDebugEnabled"];
+ if (debugOn) NSLog(@"Note: SOPE selector invocation debug is enabled.");
/* per default selector invocations are public */
[[self soClassSecurityInfo] declareObjectPublic];
}
- (id)init {
- if ((self = [super init])) {
+ if ((self = [super init]) != nil) {
[self setDoesAddContextParameter:YES];
}
return self;
qppath = [_spec objectAtIndex:i];
value = [qppath isNotNull] ? [soapEnvelope lookupQueryPath:qppath] : nil;
- [args addObject:(value != nil ? value : [NSNull null])];
+ [args addObject:(value != nil ? value : (id)[NSNull null])];
}
return args;
}
[_ctx soRequestType]];
}
if ([self doesAddContextParameter])
- args = [NSArray arrayWithObject:(_ctx ? _ctx : [NSNull null])];
+ args = [NSArray arrayWithObject:(_ctx ? _ctx : (id)[NSNull null])];
}
else {
args = [self extractArgumentsFromContext:_ctx
specification:argspec];
if (debugOn) [self debugWithFormat:@"extracted args %@", args];
if ([self doesAddContextParameter]) {
- args = args != nil
- ? [args arrayByAddingObject:(_ctx ? _ctx : [NSNull null])]
- : [NSArray arrayWithObject:(_ctx ? _ctx : [NSNull null])];
+ if (args != nil)
+ args = [args arrayByAddingObject:(_ctx != nil?_ctx:(id)[NSNull null])];
+ else
+ args = [NSArray arrayWithObject: (_ctx != nil?_ctx:(id)[NSNull null])];
}
}
// step B: validate arguments!
if ([self doesAddContextParameter])
- _args = [_args arrayByAddingObject:_ctx ? _ctx : [NSNull null]];
+ _args = [_args arrayByAddingObject:_ctx ? _ctx : (id)[NSNull null]];
if (debugOn) {
[self debugWithFormat:@"call on %@ with args(%i) %@ context %@",