Re: XML-RPC calls in Cocoa - alternative to CURLHandle?
Re: XML-RPC calls in Cocoa - alternative to CURLHandle?
- Subject: Re: XML-RPC calls in Cocoa - alternative to CURLHandle?
- From: Bjoern Kriews <email@hidden>
- Date: Mon, 15 Mar 2004 21:40:12 +0100
On 15.03.2004, at 02:56, Ryan McGann wrote:
I'm looking at Brent Simmons' XMLRPCCocoa for making XML-RPC calls. It
looks pretty useful, but uses CURLHandle to actually send the request.
Since I'd rather not have to bundle this bulky framework with my app,
does anyone have any suggestions for alternatives? Would NSURLProtocol
do the job?
Look at WSMethodInvocation, inside of the CoreServices framework. It's
a C framework, not Objective-C, but it is built into Mac OS X as of
Jaguar. The C API is pretty good; it conforms to the CoreFoundation
API standards and can easily be wrapped if so desired.
When you try to use authentication with WSMethodInvocation you will run
into problems#
because you can not set the kWSHTTPMessage because in Panther the
symbol that should
expose the constant is defined as local in the framework.
I have filed this as a bug (still open) and I know of two workarounds.
Here is some code I have written to do SQL over XML-RPC (you will have
to strip the ResultSet stuff):
The stuff regarding error domain detection is based on documented
behaviour with some observation.
If someone has figured out how to get at the SSLContextRef that one
could use to influence HTTPS behaviour
_please_ post it here or email me.
Regards, Bjoern
- (ResultSet *) executeCommand: command connection: (id) connection
{
NSURL *rpcURL = [connection valueForKey: @"URL"];
NSString *methodName = [connection valueForKey: @"methodName"];
NSString *userName = [connection valueForKey: @"userName"];
NSString *password = [connection valueForKey: @"password"];
NSNumber *timeout = [connection valueForKey: @"timeout"];
debug(1, @"command: %@\nconnection: %@", command, connection);
if( rpcURL == nil || methodName == nil)
return [[[ResultSet alloc] initWithFaultCode: [NSNumber
numberWithInt: -1] faultString: @"need rpcURL and methodName" userInfo:
nil] autorelease];
if( timeout == nil )
timeout = [NSNumber numberWithInt: 10.0];
NSDictionary *params = [NSDictionary dictionaryWithObject: command
forKey: @"parameter1"]; // name does not matter, order is important
NSDictionary *result = nil;
NSDictionary *remoteResult = nil;
WSMethodInvocationRef rpcCall = WSMethodInvocationCreate((CFURLRef)
rpcURL, (CFStringRef) methodName, kWSXMLRPCProtocol);
WSMethodInvocationSetProperty(rpcCall,
kWSMethodInvocationTimeoutValue, (CFNumberRef) timeout);
if( userName != nil && [userName length] ) {
CFHTTPMessageRef myRequest =
CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("POST"),
(CFURLRef) rpcURL, kCFHTTPVersion1_0);
if ( ! CFHTTPMessageAddAuthentication(myRequest, NULL,
(CFStringRef) userName,
(CFStringRef) password,
kCFHTTPAuthenticationSchemeBasic, FALSE)) {
warning(@"addAuthFailed");
} else {
// kWSHTTPMessage is defined as local in WebServicesCore -
filed it as a bug in Radar
#ifdef USE_SCARY_MESSAGE_WORKAROUND
// this one works on 10.3 but I find the other one more
dependable
WSMethodInvocationSetProperty(rpcCall,
CFSTR("/kWSHTTPMessage"), myRequest);
#else
// we work around it by copying the Authorize: header from
a newly created CFHTTPMessage
CFStringRef auth =
CFHTTPMessageCopyHeaderFieldValue(myRequest, CFSTR("Authorization"));
WSMethodInvocationSetProperty(rpcCall, kWSHTTPExtraHeaders,
(CFDictionaryRef) [NSDictionary dictionaryWithObject: (NSString *)auth
forKey: @"Authorization"]);
CFRelease(auth);
#endif
}
CFRelease(myRequest);
}
WSMethodInvocationSetParameters (rpcCall, (CFDictionaryRef) params,
NULL);
// careful: result must be released (stated in docs)
result = (NSDictionary *) WSMethodInvocationInvoke (rpcCall);
NSMutableDictionary *userInfo = nil;
if ( WSMethodResultIsFault((CFDictionaryRef) result) ) {
NSNumber *faultCode = [result objectForKey: (NSString *)
kWSFaultCode];
NSString *faultString = [result objectForKey: (NSString *)
kWSFaultString];
id extra = [result objectForKey: (NSString *) kWSFaultExtra];
if( extra ) {
if( faultString == (NSString *) kWSNetworkStreamFaultString
) {
userInfo = [(NSDictionary *) extra mutableCopy];
NSNumber *error;
if( [[userInfo valueForKey: (NSString *)
kWSStreamErrorDomain] intValue] == kCFStreamErrorDomainPOSIX )
if( ( error = [userInfo valueForKey: (NSString *)
kWSStreamErrorError] ) )
[userInfo setValue: [NSString
stringWithCString: strerror( [error intValue] )] forKey:
@"posixErrorMessage" ];
} else {
userInfo = [NSDictionary dictionaryWithObject: extra
forKey: @"extra"]; // FIXME: when does this happen ?
}
}
ResultSet *resultSet = [[[ResultSet alloc] initWithFaultCode:
faultCode faultString: faultString userInfo: userInfo] autorelease];
debug(1, @"faultResultSet: %@", resultSet);
CFRelease(result);
return resultSet;
} else { // no error
remoteResult = [result objectForKey: (NSString *)
kWSMethodInvocationResult];
debug(2, @"remoteResult: %@", remoteResult);
}
ArrayResultSet *resultSet = [[ArrayResultSet alloc] initWithRows:
[remoteResult valueForKey: @"rows"] columnDescriptors: [remoteResult
valueForKey: @"columnDescriptors"]];
debug(1, @"okResultSet: %@", resultSet);
CFRelease(result);
return [resultSet autorelease];
}
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.