2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <NGXmlRpc/NGXmlRpcRequestHandler.h>
23 #include <NGXmlRpc/NGXmlRpcAction.h>
24 #include <NGXmlRpc/NGXmlRpc.h>
25 #include <NGXmlRpc/XmlRpcMethodCall+WO.h>
26 #include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
27 #include <NGObjWeb/WOApplication.h>
28 #include <NGObjWeb/WORequest.h>
29 #include <NGObjWeb/WOContext.h>
30 #include <NGObjWeb/WOResponse.h>
31 #include <NGObjWeb/WOStatisticsStore.h>
34 static BOOL perflog = NO;
35 static Class NSDateClass = Nil;
39 @interface NSObject(RPC2)
40 - (id<WOActionResults>)RPC2Action;
43 @implementation NGXmlRpcRequestHandler
46 return [super version] + 0 /* 2 */;
49 NSAssert2([super version] == 2,
50 @"invalid superclass (%@) version %i !",
51 NSStringFromClass([self superclass]), [super version]);
53 NSDateClass = [NSDate class];
54 perflog = [[NSUserDefaults standardUserDefaults]
56 @"WOProfileXmlRpcActionRequestHandler"];
60 The request handler part of a direct action URI looks like this:
62 [actionClass/]actionName[?key=value&key=value&...]
65 - (WOResponse *)_runObject:(NGXmlRpcAction *)_object
66 request:(WORequest *)_req
69 XmlRpcMethodCall *call;
71 if (_object == nil) return nil;
73 if (![[_req method] isEqualToString:@"POST"]) {
74 /* only POST is allowed ! */
78 call = [(XmlRpcMethodCall *)[XmlRpcMethodCall alloc] initWithRequest:_req];
79 call = [call autorelease];
84 content = [_req content];
86 [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
87 [self logWithFormat:@" content-len: %d", [content length]];
88 [self logWithFormat:@" encoding: %d", [_req contentEncoding]];
93 result = [[_object performMethodCall:call] generateResponse];
100 if (![result isKindOfClass:[WOResponse class]]) {
101 /* morph an object result into a XML-RPC response .. */
102 XmlRpcMethodResponse *r;
104 r = [[XmlRpcMethodResponse alloc] initWithResult:result];
105 result = [[[r generateResponse] retain] autorelease];
112 - (WOResponse *)handleRequest:(WORequest *)_request {
113 NSTimeInterval startHandling = 0.0;
115 NSAutoreleasePool *pool = nil;
118 NSString *handlerPath = nil;
119 NSString *actionClassName;
120 WOResponse *response = nil;
121 WOContext *context = nil;
123 NSMutableDictionary *threadDict;
124 Class actionClass = Nil;
126 if (![[_request method] isEqualToString:@"POST"]) {
127 [self logWithFormat:@"only POST requests are valid XML-RPC requests ..."];
132 startHandling = [[NSDateClass date] timeIntervalSince1970];
134 thread = [NSThread currentThread];
135 NSAssert(thread, @"missing current thread ...");
136 threadDict = [thread threadDictionary];
137 NSAssert(threadDict, @"missing current thread's dictionary ...");
139 if (_request == nil) return nil;
142 *(&actionClassName) = nil;
144 app = [WOApplication application];
146 handlerPath = [_request uri];
147 actionClass = [NGXmlRpcAction actionClassForURI:handlerPath];
149 if (actionClass == Nil) {
150 [self logWithFormat:@"found no action class for URI: %@", handlerPath];
151 actionClass = [app defaultActionClassForRequest:_request];
154 #if DEBUG_XMLRPC_ACTION
155 NSLog(@"[XML-RPC request handler] class=%@ ..",
160 *(&pool) = [[NSAutoreleasePool alloc] init];
164 context = [WOContext contextWithRequest:_request];
165 NSAssert(context, @"no context assigned ..");
166 NSAssert(threadDict, @"missing current thread's dictionary ...");
167 [threadDict setObject:context forKey:@"WOContext"];
172 NGXmlRpcAction *actionObject = nil;
173 id<WOActionResults> result = nil;
179 NSAutoreleasePool *pool2 = [NSAutoreleasePool new];
183 /* create direct action object */
184 actionObject = [actionClass alloc];
185 actionObject = [actionObject initWithContext:context];
186 actionObject = [actionObject autorelease];
188 if (actionObject == nil) {
190 @"ERROR: could not create direct action object of class %@",
195 result = [self _runObject:actionObject request:_request];
196 result = [(id)result retain];
200 @"WARNING: got empty result from action .."];
201 response = [WOResponse alloc];
202 response = [response initWithRequest:_request];
203 [response setStatus:500];
206 /* generate response */
207 response = [[result generateResponse] retain];
210 [(id)result release]; result = nil;
215 RELEASE(pool2); pool2 = nil;
217 response = [response autorelease];
220 response = [app handleException:localException inContext:context];
224 response = [response retain];
229 response = [app handleException:localException inContext:context];
230 response = [response retain];
234 NSAssert(threadDict, @"missing current thread's dictionary ...");
235 [threadDict removeObjectForKey:@"WOContext"];
238 [pool release]; pool = nil;
243 rt = [[NSDateClass date] timeIntervalSince1970] - startHandling;
244 NSLog(@"[da-handler]: handleRequest took %4.3fs.",
245 rt < 0.0 ? -1.0 : rt);
248 return AUTORELEASE(response);
251 @end /* NGXmlRpcRequestHandler */