mirror of
https://github.com/gnustep/libs-base.git
synced 2025-06-01 17:12:03 +00:00
Integrated XMLRPC support.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20843 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
9d92b8cef3
commit
7566f5535f
3 changed files with 1152 additions and 1 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2005-03-04 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/Additions/GSXML.m: GSXMLRPC integrated.
|
||||||
|
* Headers/Additions/GSUstepBase/GSXML.h: GSXMLRPC integrated.
|
||||||
|
|
||||||
2005-03-03 Adam Fedor <fedor@gnu.org>
|
2005-03-03 Adam Fedor <fedor@gnu.org>
|
||||||
|
|
||||||
* Source/NSFileManager.m (-createFileAtPath:...): Define var at
|
* Source/NSFileManager.m (-createFileAtPath:...): Define var at
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/** Interface for XML parsing classes
|
/** Interface for XML parsing classes
|
||||||
|
|
||||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
Copyright (C) 2000-2005 Free Software Foundation, Inc.
|
||||||
|
|
||||||
Written by: Michael Pakhantsov <mishel@berest.dp.ua> on behalf of
|
Written by: Michael Pakhantsov <mishel@berest.dp.ua> on behalf of
|
||||||
Brainstorm computer solutions.
|
Brainstorm computer solutions.
|
||||||
|
@ -403,6 +403,240 @@
|
||||||
- (GSXMLDocument*) xsltTransform: (GSXMLDocument*)xsltStylesheet;
|
- (GSXMLDocument*) xsltTransform: (GSXMLDocument*)xsltStylesheet;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <Foundation/NSURLHandle.h>
|
||||||
|
|
||||||
|
@class NSArray;
|
||||||
|
@class NSDictionary;
|
||||||
|
@class NSTimer;
|
||||||
|
@class GSXMLNode;
|
||||||
|
@class GSXMLRPC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>The GSXMLRPC class provides methods for constructing and parsing
|
||||||
|
* XMLRPC method call and response documents ... so that calls may
|
||||||
|
* be constructed of standard objects.
|
||||||
|
* </p>
|
||||||
|
* <p>The correspondence between XMLRPC values and Objective-C objects
|
||||||
|
* is as follows -
|
||||||
|
* </p>
|
||||||
|
* <list>
|
||||||
|
* <item><strong>i4</strong> (or <em>int</em>) is an [NSNumber] other
|
||||||
|
* than a real/float or boolean.</item>
|
||||||
|
* <item><strong>boolean</strong> is an [NSNumber] created as a BOOL.</item>
|
||||||
|
* <item><strong>string</strong> is an [NSString] object.</item>
|
||||||
|
* <item><strong>double</strong> is an [NSNumber] created as a float or
|
||||||
|
* double.</item>
|
||||||
|
* <item><strong>dateTime.iso8601</strong> is an [NSDate] object.</item>
|
||||||
|
* <item><strong>base64</strong> is an [NSData] object.</item>
|
||||||
|
* <item><strong>array</strong> is an [NSArray] object.</item>
|
||||||
|
* <item><strong>struct</strong> is an [NSDictionary] object.</item>
|
||||||
|
* </list>
|
||||||
|
* <p>If you attempt to use any other type of object in the construction
|
||||||
|
* of an XMLRPC document, the [NSObject-description] method of that
|
||||||
|
* object will be used to create a striong, and the resulting object
|
||||||
|
* will be encoded as an XMLRPC <em>string</em> element.
|
||||||
|
* </p>
|
||||||
|
* <p>In particular, the names of members in a <em>struct</em> must be strings,
|
||||||
|
* so if you provide an [NSDictionary] object to represent a <em>struct</em>
|
||||||
|
* the keys of the dictionary will be converted to strings if necessary.
|
||||||
|
* </p>
|
||||||
|
* <p>The class also provides a method for making a synchronous XMLRPC
|
||||||
|
* method call (with timeout), or an asynchronous call in which the
|
||||||
|
* call completion is handled by a delegate.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@interface GSXMLRPC : NSObject <NSURLHandleClient>
|
||||||
|
{
|
||||||
|
@private
|
||||||
|
NSURLHandle *handle;
|
||||||
|
NSTimer *timer;
|
||||||
|
id result;
|
||||||
|
id delegate; // Not retained.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a method name and an array of parameters, this method constructs
|
||||||
|
* the XML document for the corresponding XMLRPC call and returns the
|
||||||
|
* document as a string.<br />
|
||||||
|
* The params array may be empty or nil if there are no parameters to be
|
||||||
|
* passed.<br />
|
||||||
|
* The method returns nil if passed an invalid method name (a method name
|
||||||
|
* may contain any of the ascii alphanumeric characters and underscore,
|
||||||
|
* fullstop, colon, or slash).<br />
|
||||||
|
* This method is used internally when sending an XMLRPC method call to
|
||||||
|
* a remote system, but you can also call it yourself.
|
||||||
|
*/
|
||||||
|
- (NSString*) buildMethodCall: (NSString*)method
|
||||||
|
params: (NSArray*)params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an XML document for an XMLRPC fault response with the
|
||||||
|
* specified code and string. The resulting document is returned
|
||||||
|
* as a string.<br />
|
||||||
|
* This method is intended for use by applications acting as XMLRPC servers.
|
||||||
|
*/
|
||||||
|
- (NSString*) buildResponseWithFaultCode: (int)code andString: (NSString*)s;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an XMLRPC response with the specified array of parameters and
|
||||||
|
* returns the document as a string.<br />
|
||||||
|
* The params array may be empty or nil if there are no parameters to be
|
||||||
|
* returned (an empty params element will be created).<br />
|
||||||
|
* This method is intended for use by applications acting as XMLRPC servers.
|
||||||
|
*/
|
||||||
|
- (NSString*) buildResponseWithParams: (NSArray*)params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the delegate previously set by the -setDelegate: method.<br />
|
||||||
|
* The delegate handles completion of asynchronous method calls to the
|
||||||
|
* URL specified when the receiver was initialised (if any).
|
||||||
|
*/
|
||||||
|
- (id) delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the receiver to make XMLRPC calls to the specified URL.<br />
|
||||||
|
* This method just calls -initWithURL:certificate:privateKey:password:
|
||||||
|
* with nil arguments for the SSL credentials.
|
||||||
|
*/
|
||||||
|
- (id) initWithURL: (NSString*)url;
|
||||||
|
|
||||||
|
/** <init />
|
||||||
|
* Initialise the receiver to make XMLRPC calls to the specified url
|
||||||
|
* and (optionally) with the specified SSL parameters.<br />
|
||||||
|
* The url argument may be nil, in which case the receiver will be
|
||||||
|
* unable to make XMLRPC calls, but can be used to parse incoming
|
||||||
|
* requests and build responses.<br />
|
||||||
|
* If the SSL credentials are non-nil, connections to the remote server
|
||||||
|
* will be authenticated using the supplied certificate so that the
|
||||||
|
* remote system knows who is contacting it.
|
||||||
|
*/
|
||||||
|
- (id) initWithURL: (NSString*)url
|
||||||
|
certificate: (NSString*)cert
|
||||||
|
privateKey: (NSString*)pKey
|
||||||
|
password: (NSString*)pwd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls -sendMethodCall:params:timeout: and waits for the response.<br />
|
||||||
|
* Returns the response parameters (an array),
|
||||||
|
* the response fault (a dictionary),
|
||||||
|
* or a failure reason (a string).
|
||||||
|
*/
|
||||||
|
- (id) makeMethodCall: (NSString*)method
|
||||||
|
params: (NSArray*)params
|
||||||
|
timeout: (int)seconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses XML data containing an XMLRPC method call.<br />
|
||||||
|
* Returns the name of the method call.<br />
|
||||||
|
* Empties, and then places the method parameters (if any)
|
||||||
|
* in the params argument.<br />
|
||||||
|
* NB. Any containers (arrays or dictionaries) in the parsed parameters
|
||||||
|
* will be mutable, so you can modify this data structure as you like.<br />
|
||||||
|
* Raises an exception if parsing fails.<br />
|
||||||
|
* This method is intended for the use of XMLRPC server applications.
|
||||||
|
*/
|
||||||
|
- (NSString*) parseMethod: (NSData*)request
|
||||||
|
params: (NSMutableArray*)params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses XML data containing an XMLRPC method response.<br />
|
||||||
|
* Returns nil for succes, the fault dictionary on failure.<br />
|
||||||
|
* Places the response parameters (if any) in the params argument.<br />
|
||||||
|
* NB. Any containers (arrays or dictionaries) in the parsed parameters
|
||||||
|
* will be mutable, so you can modify this data structure as you like.<br />
|
||||||
|
* Raises an exception if parsing fails.<br />
|
||||||
|
* Used internally when making a method call to a remote server.
|
||||||
|
*/
|
||||||
|
- (NSDictionary*) parseResponse: (NSData*)response
|
||||||
|
params: (NSMutableArray*)params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the result of the last method call, or nil if there has been
|
||||||
|
* no method call or one is in progress.<br />
|
||||||
|
* The result may be one of -
|
||||||
|
* <list>
|
||||||
|
* <item>A mutable array ... the parameters of a success response.</item>
|
||||||
|
* <item>A dictionary ... containing a fault response.</item>
|
||||||
|
* <item>A string ... describing a low-level failure (eg. timeout).</item>
|
||||||
|
* </list>
|
||||||
|
* NB. Any containers (arrays or dictionaries) in the parsed parameters
|
||||||
|
* of a success response will be mutable, so you can modify this data
|
||||||
|
* structure as you like.
|
||||||
|
*/
|
||||||
|
- (id) result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an asynchronous XMLRPC method call with the specified timeout.<br />
|
||||||
|
* A delegate should have been set to handle the result of this call,
|
||||||
|
* but if one was not set the state of the asynchronous call may be polled
|
||||||
|
* by calling the -result method, which will return nil as long as the
|
||||||
|
* call has not completed.<br />
|
||||||
|
* The call may be cancelled by calling the -timeout: method<br />
|
||||||
|
* This method returns YES if the call was started,
|
||||||
|
* NO if it could not be started
|
||||||
|
* (eg because another call is in progress or because of bad arguments).<br />
|
||||||
|
* NB. For the asynchronous operation to proceed, the current [NSRunLoop]
|
||||||
|
* must be run.
|
||||||
|
*/
|
||||||
|
- (BOOL) sendMethodCall: (NSString*)method
|
||||||
|
params: (NSArray*)params
|
||||||
|
timeout: (int)seconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether to perform mdebug trace on I/O
|
||||||
|
*/
|
||||||
|
- (void) setDebug: (BOOL)flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the delegate object which will receive callbacks when an XMLRPC
|
||||||
|
* call completes.<br />
|
||||||
|
* NB. this delegate is <em>not</em> retained, and should be removed
|
||||||
|
* before it is deallocated (call -setDelegate: again with a nil argument
|
||||||
|
* to remove the delegate).
|
||||||
|
*/
|
||||||
|
- (void) setDelegate: (id)aDelegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles timeouts, passing information to delegate ... you don't need to
|
||||||
|
* call this method, but you <em>may</em> call it in order to cancel an
|
||||||
|
* asynchronous request as if it had timed out.
|
||||||
|
*/
|
||||||
|
- (void) timeout: (NSTimer*)t;
|
||||||
|
|
||||||
|
|
||||||
|
/** Allows GSXMLRPC to act as a client of NSURLHandle. Internal use only. */
|
||||||
|
- (void) URLHandle: (NSURLHandle*)sender
|
||||||
|
resourceDataDidBecomeAvailable: (NSData*)newData;
|
||||||
|
/** Allows GSXMLRPC to act as a client of NSURLHandle. Internal use only. */
|
||||||
|
- (void) URLHandle: (NSURLHandle*)sender
|
||||||
|
resourceDidFailLoadingWithReason: (NSString*)reason;
|
||||||
|
/** Allows GSXMLRPC to act as a client of NSURLHandle. Internal use only. */
|
||||||
|
- (void) URLHandleResourceDidBeginLoading: (NSURLHandle*)sender;
|
||||||
|
/** Allows GSXMLRPC to act as a client of NSURLHandle. Internal use only. */
|
||||||
|
- (void) URLHandleResourceDidCancelLoading: (NSURLHandle*)sender;
|
||||||
|
/** Allows GSXMLRPC to act as a client of NSURLHandle. Internal use only. */
|
||||||
|
- (void) URLHandleResourceDidFinishLoading: (NSURLHandle*)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates should implement this method in order to be informed of
|
||||||
|
* the success or failure of an XMLRPC method call which was initiated
|
||||||
|
* by the -sendMethodCall:params:timeout: method.<br />
|
||||||
|
*/
|
||||||
|
@interface GSXMLRPC (Delegate)
|
||||||
|
/**
|
||||||
|
* Called by the sender when an XMLRPC method call completes (either success
|
||||||
|
* or failure).
|
||||||
|
* The delegate may then call the -result method to retrieve the result of
|
||||||
|
* the method call from the sender.
|
||||||
|
*/
|
||||||
|
- (void) completedXMLRPC: (GSXMLRPC*)sender;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
#endif /* STRICT_MACOS_X */
|
#endif /* STRICT_MACOS_X */
|
||||||
#endif /* STRICT_OPENSTEP */
|
#endif /* STRICT_OPENSTEP */
|
||||||
|
|
||||||
|
|
|
@ -4308,3 +4308,915 @@ static BOOL warned = NO; if (warned == NO) { warned = YES; NSLog(@"WARNING, use
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <Foundation/NSArray.h>
|
||||||
|
#include <Foundation/NSCalendarDate.h>
|
||||||
|
#include <Foundation/NSCharacterSet.h>
|
||||||
|
#include <Foundation/NSData.h>
|
||||||
|
#include <Foundation/NSDate.h>
|
||||||
|
#include <Foundation/NSDictionary.h>
|
||||||
|
#include <Foundation/NSException.h>
|
||||||
|
#include <Foundation/NSRunLoop.h>
|
||||||
|
#include <Foundation/NSString.h>
|
||||||
|
#include <Foundation/NSTimeZone.h>
|
||||||
|
#include <Foundation/NSTimer.h>
|
||||||
|
#include <Foundation/NSURL.h>
|
||||||
|
#include <Foundation/NSURLHandle.h>
|
||||||
|
#include <Foundation/NSValue.h>
|
||||||
|
|
||||||
|
#include <GNUstepBase/GSMime.h>
|
||||||
|
#include <GNUstepBase/GSXML.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Categories on other classes which are required for XMLRPC
|
||||||
|
*/
|
||||||
|
@interface NSArray (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSData (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSDate (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSDictionary (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSObject (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSNumber (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSString (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent;
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A little code to handle indentation.
|
||||||
|
*/
|
||||||
|
static NSString *indentations[] = {
|
||||||
|
@" ",
|
||||||
|
@" ",
|
||||||
|
@" ",
|
||||||
|
@"\t",
|
||||||
|
@"\t ",
|
||||||
|
@"\t ",
|
||||||
|
@"\t ",
|
||||||
|
@"\t\t",
|
||||||
|
@"\t\t ",
|
||||||
|
@"\t\t ",
|
||||||
|
@"\t\t ",
|
||||||
|
@"\t\t\t",
|
||||||
|
@"\t\t\t ",
|
||||||
|
@"\t\t\t ",
|
||||||
|
@"\t\t\t ",
|
||||||
|
@"\t\t\t\t"
|
||||||
|
};
|
||||||
|
static void indentation(unsigned level, NSMutableString *str)
|
||||||
|
{
|
||||||
|
if (level > 0)
|
||||||
|
{
|
||||||
|
if (level >= sizeof(indentations)/sizeof(*indentations))
|
||||||
|
{
|
||||||
|
level = sizeof(indentations)/sizeof(*indentations) - 1;
|
||||||
|
}
|
||||||
|
[str appendString: indentations[level]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implementation of categories to output objects for XMLRPC
|
||||||
|
*/
|
||||||
|
|
||||||
|
@implementation NSArray (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
unsigned c = [self count];
|
||||||
|
|
||||||
|
indentation(indent++, str);
|
||||||
|
[str appendString: @"<array>\n"];
|
||||||
|
indentation(indent++, str);
|
||||||
|
[str appendString: @"<data>\n"];
|
||||||
|
for (i = 0; i < c; i++)
|
||||||
|
{
|
||||||
|
id value = [self objectAtIndex: i];
|
||||||
|
|
||||||
|
indentation(indent++, str);
|
||||||
|
[str appendString: @"<value>\n"];
|
||||||
|
[value appendToXMLRPC: str indent: indent];
|
||||||
|
[str appendString: @"\n"];
|
||||||
|
indentation(--indent, str);
|
||||||
|
[str appendString: @"</value>\n"];
|
||||||
|
}
|
||||||
|
indentation(--indent, str);
|
||||||
|
[str appendString: @"</data>\n"];
|
||||||
|
indentation(--indent, str);
|
||||||
|
[str appendString: @"</array>"];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSData (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
NSData *d;
|
||||||
|
NSString *s;
|
||||||
|
|
||||||
|
d = [GSMimeDocument encodeBase64: self];
|
||||||
|
s = [[NSString alloc] initWithData: d encoding: NSASCIIStringEncoding];
|
||||||
|
[str appendString: @"<base64>"];
|
||||||
|
[str appendString: s];
|
||||||
|
[str appendString: @"</base64>"];
|
||||||
|
RELEASE(s);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSDate (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
static NSTimeZone *z = nil;
|
||||||
|
NSString *s;
|
||||||
|
|
||||||
|
if (z == nil)
|
||||||
|
{
|
||||||
|
s = RETAIN([NSTimeZone timeZoneForSecondsFromGMT: 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
s = [self descriptionWithCalendarFormat: @"%Y%m%dT%H:%M:%S"
|
||||||
|
timeZone: z
|
||||||
|
locale: nil];
|
||||||
|
[str appendString: @"<dateTime.iso8601>"];
|
||||||
|
[str appendString: s];
|
||||||
|
[str appendString: @"</dateTime.iso8601>"];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSDictionary (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
NSEnumerator *kEnum = [self keyEnumerator];
|
||||||
|
NSString *key;
|
||||||
|
|
||||||
|
indentation(indent++, str);
|
||||||
|
[str appendString: @"<struct>\n"];
|
||||||
|
while ((key = [kEnum nextObject]))
|
||||||
|
{
|
||||||
|
id value = [self objectForKey: key];
|
||||||
|
|
||||||
|
indentation(indent++, str);
|
||||||
|
[str appendString: @"<member>\n"];
|
||||||
|
indentation(indent, str);
|
||||||
|
[str appendString: @"<name>"];
|
||||||
|
[str appendString: [[key description] stringByEscapingXML]];
|
||||||
|
[str appendString: @"</name>\n"];
|
||||||
|
indentation(indent++, str);
|
||||||
|
[str appendString: @"<value>\n"];
|
||||||
|
[value appendToXMLRPC: str indent: indent--];
|
||||||
|
[str appendString: @"\n"];
|
||||||
|
indentation(indent--, str);
|
||||||
|
[str appendString: @"</value>\n"];
|
||||||
|
indentation(indent, str);
|
||||||
|
[str appendString: @"</member>\n"];
|
||||||
|
}
|
||||||
|
indentation(--indent, str);
|
||||||
|
[str appendString: @"</struct>"];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSNumber (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
const char *t = [self objCType];
|
||||||
|
|
||||||
|
indentation(indent, str);
|
||||||
|
if (strchr("cCsSiIlL", *t) != 0)
|
||||||
|
{
|
||||||
|
long i = [self longValue];
|
||||||
|
|
||||||
|
if ((i == 0 || i == 1) && (*t == 'c' || *t == 'C'))
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
[str appendString: @"<boolean>0</boolean>"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[str appendString: @"<boolean>1</boolean>"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[str appendFormat: @"<i4>%d</i4>", i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[str appendFormat: @"<double>%f</double>", [self doubleValue]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSObject (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
[[self description] appendToXMLRPC: str indent: indent];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSString (GSXMLRPC)
|
||||||
|
- (void) appendToXMLRPC: (NSMutableString*)str indent: (unsigned)indent
|
||||||
|
{
|
||||||
|
indentation(indent, str);
|
||||||
|
[str appendFormat: @"<string>%@</string>", [self stringByEscapingXML]];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert incoming XMLRPC value to a normal Objective-C object.
|
||||||
|
*/
|
||||||
|
@interface GSXMLRPC (Private)
|
||||||
|
- (id) _parseValue: (GSXMLNode*)node;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GSXMLRPC (Private)
|
||||||
|
- (id) _parseValue: (GSXMLNode*)node
|
||||||
|
{
|
||||||
|
NSString *name = [node name];
|
||||||
|
NSString *str;
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"value"])
|
||||||
|
{
|
||||||
|
GSXMLNode *type = [node firstChildElement];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A value with no type element is just a string.
|
||||||
|
*/
|
||||||
|
if (type == nil)
|
||||||
|
{
|
||||||
|
name = @"string";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = type;
|
||||||
|
name = [node name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name length] == 0)
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"i4"] || [name isEqualToString: @"int"])
|
||||||
|
{
|
||||||
|
str = [node content];
|
||||||
|
if (str == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"missing %@ value", name];
|
||||||
|
}
|
||||||
|
return [NSNumber numberWithInt: [str intValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"string"])
|
||||||
|
{
|
||||||
|
str = [node content];
|
||||||
|
if (str == nil)
|
||||||
|
{
|
||||||
|
str = @"";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"boolean"])
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
|
||||||
|
str = [node content];
|
||||||
|
if (str == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"missing %@ value", name];
|
||||||
|
}
|
||||||
|
c = [str intValue];
|
||||||
|
return [NSNumber numberWithBool: c == 0 ? NO : YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"double"])
|
||||||
|
{
|
||||||
|
str = [node content];
|
||||||
|
if (str == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"missing %@ value", name];
|
||||||
|
}
|
||||||
|
return [NSNumber numberWithDouble: [str doubleValue]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"data"])
|
||||||
|
{
|
||||||
|
NSData *d;
|
||||||
|
|
||||||
|
str = [node content];
|
||||||
|
if (str == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"missing %@ value", name];
|
||||||
|
}
|
||||||
|
d = [str dataUsingEncoding: NSASCIIStringEncoding];
|
||||||
|
return [GSMimeDocument decodeBase64: d];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"date"])
|
||||||
|
{
|
||||||
|
str = [node content];
|
||||||
|
if (str == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"missing %@ value", name];
|
||||||
|
}
|
||||||
|
return [NSCalendarDate dateWithString: str
|
||||||
|
calendarFormat: @"%Y%m%dT%H:%M:%S"
|
||||||
|
locale: nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"array"])
|
||||||
|
{
|
||||||
|
NSMutableArray *arr = [NSMutableArray array];
|
||||||
|
|
||||||
|
node = [node firstChildElement];
|
||||||
|
while (node != nil && [[node name] isEqualToString: @"data"] == NO)
|
||||||
|
{
|
||||||
|
node = [node nextElement];
|
||||||
|
}
|
||||||
|
if ([[node name] isEqualToString: @"data"] == YES)
|
||||||
|
{
|
||||||
|
node = [node firstChildElement];
|
||||||
|
while (node != nil)
|
||||||
|
{
|
||||||
|
if ([[node name] isEqualToString: @"value"] == YES)
|
||||||
|
{
|
||||||
|
id v;
|
||||||
|
|
||||||
|
v = [self _parseValue: node];
|
||||||
|
if (v != nil)
|
||||||
|
{
|
||||||
|
[arr addObject: v];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = [node nextElement];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([name isEqualToString: @"struct"])
|
||||||
|
{
|
||||||
|
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
node = [node firstChildElement];
|
||||||
|
while (node != nil)
|
||||||
|
{
|
||||||
|
if ([[node name] isEqualToString: @"member"] == YES)
|
||||||
|
{
|
||||||
|
GSXMLNode *member = [node firstChildElement];
|
||||||
|
NSString *key = nil;
|
||||||
|
id val = nil;
|
||||||
|
|
||||||
|
while (member != nil)
|
||||||
|
{
|
||||||
|
if ([[member name] isEqualToString: @"name"] == YES)
|
||||||
|
{
|
||||||
|
key = [member content];
|
||||||
|
}
|
||||||
|
else if ([[member name] isEqualToString: @"value"] == YES)
|
||||||
|
{
|
||||||
|
val = [self _parseValue: member];
|
||||||
|
}
|
||||||
|
if (key != nil && val != nil)
|
||||||
|
{
|
||||||
|
[dict setObject: val forKey: key];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
member = [member nextElement];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = [node nextElement];
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"Unknown value type: %@", name];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And now, the actual GSXMLRPC class.
|
||||||
|
*/
|
||||||
|
@implementation GSXMLRPC
|
||||||
|
|
||||||
|
- (NSString*) buildMethodCall: (NSString*)method
|
||||||
|
params: (NSArray*)params
|
||||||
|
{
|
||||||
|
NSMutableString *str = [NSMutableString stringWithCapacity: 1024];
|
||||||
|
unsigned c = [params count];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if ([method length] == 0)
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static NSCharacterSet *illegal = nil;
|
||||||
|
NSRange r;
|
||||||
|
|
||||||
|
if (illegal == nil)
|
||||||
|
{
|
||||||
|
NSMutableCharacterSet *tmp = [NSMutableCharacterSet new];
|
||||||
|
|
||||||
|
[tmp addCharactersInRange: NSMakeRange('0', 10)];
|
||||||
|
[tmp addCharactersInRange: NSMakeRange('a', 26)];
|
||||||
|
[tmp addCharactersInRange: NSMakeRange('A', 26)];
|
||||||
|
[tmp addCharactersInString: @"_.:/"];
|
||||||
|
[tmp invert];
|
||||||
|
illegal = [tmp copy];
|
||||||
|
RELEASE(tmp);
|
||||||
|
}
|
||||||
|
r = [method rangeOfCharacterFromSet: illegal];
|
||||||
|
if (r.length > 0)
|
||||||
|
{
|
||||||
|
return nil; // Bad method name.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[str appendString: @"<?xml version=\"1.0\"?>\n"];
|
||||||
|
[str appendString: @"<methodCall>\n"];
|
||||||
|
[str appendFormat: @" <methodName>%@</methodName>\n",
|
||||||
|
[method stringByEscapingXML]];
|
||||||
|
if (c > 0)
|
||||||
|
{
|
||||||
|
[str appendString: @" <params>\n"];
|
||||||
|
for (i = 0; i < c; i++)
|
||||||
|
{
|
||||||
|
[str appendString: @" <param>\n"];
|
||||||
|
[str appendString: @" <value>\n"];
|
||||||
|
[[params objectAtIndex: i] appendToXMLRPC: str indent: 3];
|
||||||
|
[str appendString: @"\n </value>\n"];
|
||||||
|
[str appendString: @" </param>\n"];
|
||||||
|
}
|
||||||
|
[str appendString: @" </params>\n"];
|
||||||
|
}
|
||||||
|
[str appendString: @"</methodCall>\n"];
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*) buildResponseWithFaultCode: (int)code andString: (NSString*)s
|
||||||
|
{
|
||||||
|
NSMutableString *str = [NSMutableString stringWithCapacity: 1024];
|
||||||
|
NSDictionary *fault;
|
||||||
|
|
||||||
|
fault = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
[NSNumber numberWithInt: code], @"faultCode",
|
||||||
|
[s stringByEscapingXML], @"faultString",
|
||||||
|
nil];
|
||||||
|
|
||||||
|
[str appendString: @"<?xml version=\"1.0\"?>\n"];
|
||||||
|
[str appendString: @"<methodResponse>\n"];
|
||||||
|
[str appendString: @" <fault>\n"];
|
||||||
|
[str appendString: @" <value>\n"];
|
||||||
|
[fault appendToXMLRPC: str indent: 3];
|
||||||
|
[str appendString: @"\n </value>\n"];
|
||||||
|
[str appendString: @" </fault>\n"];
|
||||||
|
[str appendString: @"</methodResponse>\n"];
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*) buildResponseWithParams: (NSArray*)params
|
||||||
|
{
|
||||||
|
NSMutableString *str = [NSMutableString stringWithCapacity: 1024];
|
||||||
|
unsigned c = [params count];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
[str appendString: @"<?xml version=\"1.0\"?>\n"];
|
||||||
|
[str appendString: @"<methodResponse>\n"];
|
||||||
|
[str appendString: @" <params>\n"];
|
||||||
|
for (i = 0; i < c; i++)
|
||||||
|
{
|
||||||
|
[str appendString: @" <param>\n"];
|
||||||
|
[str appendString: @" <value>\n"];
|
||||||
|
[[params objectAtIndex: i] appendToXMLRPC: str indent: 3];
|
||||||
|
[str appendString: @"\n </value>\n"];
|
||||||
|
[str appendString: @" </param>\n"];
|
||||||
|
}
|
||||||
|
[str appendString: @" </params>\n"];
|
||||||
|
[str appendString: @"</methodResponse>\n"];
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
if (timer != nil)
|
||||||
|
{
|
||||||
|
[self timeout: nil]; // Treat as immediate timeout.
|
||||||
|
}
|
||||||
|
[handle removeClient: self];
|
||||||
|
DESTROY(result);
|
||||||
|
DESTROY(handle);
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) delegate
|
||||||
|
{
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithURL: (NSString*)url
|
||||||
|
{
|
||||||
|
return [self initWithURL: url certificate: nil privateKey: nil password: nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithURL: (NSString*)url
|
||||||
|
certificate: (NSString*)cert
|
||||||
|
privateKey: (NSString*)pKey
|
||||||
|
password: (NSString*)pwd
|
||||||
|
{
|
||||||
|
if (url != nil)
|
||||||
|
{
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
NSURL *u = [NSURL URLWithString: url];
|
||||||
|
|
||||||
|
handle = RETAIN([u URLHandleUsingCache: NO]);
|
||||||
|
if (cert != nil && pKey != nil && pwd != nil)
|
||||||
|
{
|
||||||
|
[handle writeProperty: cert
|
||||||
|
forKey: GSHTTPPropertyCertificateFileKey];
|
||||||
|
[handle writeProperty: pKey forKey: GSHTTPPropertyKeyFileKey];
|
||||||
|
[handle writeProperty: pwd forKey: GSHTTPPropertyPasswordKey];
|
||||||
|
}
|
||||||
|
[handle addClient: self];
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
DESTROY(self);
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
return [self initWithURL: nil certificate: nil privateKey: nil password: nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) makeMethodCall: (NSString*)method
|
||||||
|
params: (NSArray*)params
|
||||||
|
timeout: (int)seconds
|
||||||
|
{
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
if ([self sendMethodCall: method params: params timeout: seconds] == YES)
|
||||||
|
{
|
||||||
|
NSDate *when = AUTORELEASE(RETAIN([timer fireDate]));
|
||||||
|
|
||||||
|
while (timer != nil)
|
||||||
|
{
|
||||||
|
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
||||||
|
beforeDate: when];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
ASSIGN(result, [localException description]);
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*) parseMethod: (NSData*)request
|
||||||
|
params: (NSMutableArray*)params
|
||||||
|
{
|
||||||
|
GSXPathContext *ctx = nil;
|
||||||
|
GSXPathNodeSet *ns = nil;
|
||||||
|
NSString *method;
|
||||||
|
|
||||||
|
[params removeAllObjects];
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
GSXMLParser *parser = [GSXMLParser parserWithData: request];
|
||||||
|
GSXMLDocument *doc = nil;
|
||||||
|
|
||||||
|
[parser substituteEntities: YES];
|
||||||
|
[parser parse];
|
||||||
|
doc = [parser document];
|
||||||
|
ctx = AUTORELEASE([[GSXPathContext alloc] initWithDocument: doc]);
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
ctx = nil;
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
if (ctx == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"Bad Request: parse failed"];
|
||||||
|
}
|
||||||
|
|
||||||
|
ns = (GSXPathNodeSet*)[ctx evaluateExpression: @"//methodCall/methodName"];
|
||||||
|
if ([ns count] != 1)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"Badly formatted methodCall"];
|
||||||
|
}
|
||||||
|
method = [[ns nodeAtIndex: 0] content];
|
||||||
|
|
||||||
|
ns = (GSXPathNodeSet*)[ctx evaluateExpression:
|
||||||
|
@"//methodCall/params/param/value"];
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < [ns count]; i++)
|
||||||
|
{
|
||||||
|
GSXMLNode *node = [ns nodeAtIndex: i];
|
||||||
|
|
||||||
|
if ([[node name] isEqualToString: @"value"]
|
||||||
|
&& [node firstChildElement] != nil)
|
||||||
|
{
|
||||||
|
id value = [self _parseValue: [node firstChildElement]];
|
||||||
|
|
||||||
|
if (value != nil)
|
||||||
|
{
|
||||||
|
[params addObject: value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
[params removeAllObjects];
|
||||||
|
[localException raise];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary*) parseResponse: (NSData*) response
|
||||||
|
params: (NSMutableArray*)params
|
||||||
|
{
|
||||||
|
GSXPathContext *ctx = nil;
|
||||||
|
GSXPathNodeSet *ns = nil;
|
||||||
|
id fault = nil;
|
||||||
|
|
||||||
|
[params removeAllObjects];
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
GSXMLParser *parser = [GSXMLParser parserWithData: response];
|
||||||
|
GSXMLDocument *doc = nil;
|
||||||
|
|
||||||
|
[parser substituteEntities: YES];
|
||||||
|
[parser parse];
|
||||||
|
doc = [parser document];
|
||||||
|
ctx = AUTORELEASE([[GSXPathContext alloc] initWithDocument: doc]);
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
ctx = nil;
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
if (ctx == nil)
|
||||||
|
{
|
||||||
|
[NSException raise: NSInvalidArgumentException
|
||||||
|
format: @"Bad Response: parse failed"];
|
||||||
|
}
|
||||||
|
|
||||||
|
ns = (GSXPathNodeSet*)[ctx evaluateExpression:
|
||||||
|
@"//methodResponse/params/param/value"];
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ([ns count] > 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < [ns count]; i++)
|
||||||
|
{
|
||||||
|
GSXMLNode *node = [ns nodeAtIndex: i];
|
||||||
|
|
||||||
|
if ([[node name] isEqualToString: @"value"]
|
||||||
|
&& [node firstChildElement] != nil)
|
||||||
|
{
|
||||||
|
id value = [self _parseValue: [node firstChildElement]];
|
||||||
|
|
||||||
|
if (value != nil)
|
||||||
|
{
|
||||||
|
[params addObject: value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ns = (GSXPathNodeSet*)[ctx evaluateExpression:
|
||||||
|
@"//methodResponse/fault/value/struct"];
|
||||||
|
if ([ns count] > 0)
|
||||||
|
{
|
||||||
|
fault = [self _parseValue: [ns nodeAtIndex: 0]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
[params removeAllObjects];
|
||||||
|
[localException raise];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
|
||||||
|
return fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) result
|
||||||
|
{
|
||||||
|
if (timer == nil)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) sendMethodCall: (NSString*)method
|
||||||
|
params: (NSArray*)params
|
||||||
|
timeout: (int)seconds
|
||||||
|
{
|
||||||
|
NSString *xml;
|
||||||
|
NSData *data;
|
||||||
|
|
||||||
|
ASSIGN(result, @"unable to send");
|
||||||
|
|
||||||
|
if (handle == nil)
|
||||||
|
{
|
||||||
|
return NO; // Not initialised to send.
|
||||||
|
}
|
||||||
|
if (timer != nil)
|
||||||
|
{
|
||||||
|
return NO; // Send already in progress.
|
||||||
|
}
|
||||||
|
xml = [self buildMethodCall: method params: params];
|
||||||
|
if (xml == nil)
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
data = [xml dataUsingEncoding: NSUTF8StringEncoding];
|
||||||
|
|
||||||
|
timer = [NSTimer scheduledTimerWithTimeInterval: seconds
|
||||||
|
target: self
|
||||||
|
selector: @selector(timeout:)
|
||||||
|
userInfo: nil
|
||||||
|
repeats: NO];
|
||||||
|
|
||||||
|
[handle writeProperty: @"POST" forKey: GSHTTPPropertyMethodKey];
|
||||||
|
[handle writeProperty: @"GSXMLRPC/1.0.0" forKey: @"User-Agent"];
|
||||||
|
[handle writeProperty: @"text/xml" forKey: @"Content-Type"];
|
||||||
|
[handle writeData: data];
|
||||||
|
[handle loadInBackground];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setDebug: (BOOL)flag
|
||||||
|
{
|
||||||
|
if ([handle respondsToSelector: _cmd] == YES)
|
||||||
|
{
|
||||||
|
[(id)handle setDebug: flag];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setDelegate: (id)aDelegate
|
||||||
|
{
|
||||||
|
delegate = aDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) timeout: (NSTimer*)t
|
||||||
|
{
|
||||||
|
[timer invalidate];
|
||||||
|
timer = nil;
|
||||||
|
[handle cancelLoadInBackground];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void) URLHandle: (NSURLHandle*)sender
|
||||||
|
resourceDataDidBecomeAvailable: (NSData*)newData
|
||||||
|
{
|
||||||
|
// Not interesting
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) URLHandle: (NSURLHandle*)sender
|
||||||
|
resourceDidFailLoadingWithReason: (NSString*)reason
|
||||||
|
{
|
||||||
|
ASSIGN(result, reason);
|
||||||
|
[timer invalidate];
|
||||||
|
timer = nil;
|
||||||
|
if ([delegate respondsToSelector: @selector(completedXMLRPC:)])
|
||||||
|
{
|
||||||
|
[delegate completedXMLRPC: self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) URLHandleResourceDidBeginLoading: (NSURLHandle*)sender
|
||||||
|
{
|
||||||
|
// Not interesting
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) URLHandleResourceDidCancelLoading: (NSURLHandle*)sender
|
||||||
|
{
|
||||||
|
ASSIGN(result, @"timeout");
|
||||||
|
[timer invalidate];
|
||||||
|
timer = nil;
|
||||||
|
if ([delegate respondsToSelector: @selector(completedXMLRPC:)])
|
||||||
|
{
|
||||||
|
[delegate completedXMLRPC: self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) URLHandleResourceDidFinishLoading: (NSURLHandle*)sender
|
||||||
|
{
|
||||||
|
NSMutableArray *params = [NSMutableArray array];
|
||||||
|
id fault = nil;
|
||||||
|
int code;
|
||||||
|
|
||||||
|
code = [[handle propertyForKey: NSHTTPPropertyStatusCodeKey] intValue];
|
||||||
|
|
||||||
|
if (code == 200)
|
||||||
|
{
|
||||||
|
NSData *response = [handle availableResourceData];
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
fault = [self parseResponse: response params: params];
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
fault = [localException reason];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fault = [NSString stringWithFormat: @"HTTP status %03d", code];
|
||||||
|
}
|
||||||
|
if (fault == nil)
|
||||||
|
{
|
||||||
|
ASSIGN(result, params);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSIGN(result, fault);
|
||||||
|
}
|
||||||
|
|
||||||
|
[timer invalidate];
|
||||||
|
timer = nil;
|
||||||
|
|
||||||
|
if ([delegate respondsToSelector: @selector(completedXMLRPC:)])
|
||||||
|
{
|
||||||
|
[delegate completedXMLRPC: self];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GSXMLRPC (Delegate)
|
||||||
|
- (void) completedXMLRPC: (GSXMLRPC*)sender
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue