2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include <NGXmlRpc/NGXmlRpcRequestHandler.h>
24 #include <NGXmlRpc/NGXmlRpcAction.h>
25 #include <NGXmlRpc/NGXmlRpc.h>
26 #include <NGXmlRpc/XmlRpcMethodCall+WO.h>
27 #include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
28 #include <NGObjWeb/WOApplication.h>
29 #include <NGObjWeb/WORequest.h>
30 #include <NGObjWeb/WOContext.h>
31 #include <NGObjWeb/WOResponse.h>
32 #include <NGObjWeb/WOStatisticsStore.h>
35 static BOOL perflog = NO;
36 static Class NSDateClass = Nil;
40 @interface NSObject(RPC2)
41 - (id<WOActionResults>)RPC2Action;
44 @implementation NGXmlRpcRequestHandler
47 return [super version] + 0 /* 2 */;
50 NSAssert2([super version] == 2,
51 @"invalid superclass (%@) version %i !",
52 NSStringFromClass([self superclass]), [super version]);
54 NSDateClass = [NSDate class];
55 perflog = [[NSUserDefaults standardUserDefaults]
57 @"WOProfileXmlRpcActionRequestHandler"];
61 The request handler part of a direct action URI looks like this:
63 [actionClass/]actionName[?key=value&key=value&...]
66 - (WOResponse *)_runObject:(NGXmlRpcAction *)_object
67 request:(WORequest *)_req
70 XmlRpcMethodCall *call;
72 if (_object == nil) return nil;
74 if (![[_req method] isEqualToString:@"POST"]) {
75 /* only POST is allowed ! */
79 call = [(XmlRpcMethodCall *)[XmlRpcMethodCall alloc] initWithRequest:_req];
80 call = [call autorelease];
85 content = [_req content];
87 [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
88 [self logWithFormat:@" content-len: %d", [content length]];
89 [self logWithFormat:@" encoding: %d", [_req contentEncoding]];
94 result = [[_object performMethodCall:call] generateResponse];
101 if (![result isKindOfClass:[WOResponse class]]) {
102 /* morph an object result into a XML-RPC response .. */
103 XmlRpcMethodResponse *r;
105 r = [[XmlRpcMethodResponse alloc] initWithResult:result];
106 result = [[[r generateResponse] retain] autorelease];
113 - (WOResponse *)handleRequest:(WORequest *)_request {
114 NSTimeInterval startHandling = 0.0;
116 NSAutoreleasePool *pool = nil;
119 NSString *handlerPath = nil;
120 NSString *actionClassName;
121 WOResponse *response = nil;
122 WOContext *context = nil;
124 NSMutableDictionary *threadDict;
125 Class actionClass = Nil;
127 if (![[_request method] isEqualToString:@"POST"]) {
128 [self logWithFormat:@"only POST requests are valid XML-RPC requests ..."];
133 startHandling = [[NSDateClass date] timeIntervalSince1970];
135 thread = [NSThread currentThread];
136 NSAssert(thread, @"missing current thread ...");
137 threadDict = [thread threadDictionary];
138 NSAssert(threadDict, @"missing current thread's dictionary ...");
140 if (_request == nil) return nil;
143 *(&actionClassName) = nil;
145 app = [WOApplication application];
147 handlerPath = [_request uri];
148 actionClass = [NGXmlRpcAction actionClassForURI:handlerPath];
150 if (actionClass == Nil) {
151 [self logWithFormat:@"found no action class for URI: %@", handlerPath];
152 actionClass = [app defaultActionClassForRequest:_request];
155 #if DEBUG_XMLRPC_ACTION
156 NSLog(@"[XML-RPC request handler] class=%@ ..",
161 *(&pool) = [[NSAutoreleasePool alloc] init];
165 context = [WOContext contextWithRequest:_request];
166 NSAssert(context, @"no context assigned ..");
167 NSAssert(threadDict, @"missing current thread's dictionary ...");
168 [threadDict setObject:context forKey:@"WOContext"];
173 NGXmlRpcAction *actionObject = nil;
174 id<WOActionResults> result = nil;
180 NSAutoreleasePool *pool2 = [NSAutoreleasePool new];
184 /* create direct action object */
185 actionObject = [actionClass alloc];
186 actionObject = [actionObject initWithContext:context];
187 actionObject = [actionObject autorelease];
189 if (actionObject == nil) {
191 @"ERROR: could not create direct action object of class %@",
196 result = [self _runObject:actionObject request:_request];
197 result = [(id)result retain];
201 @"WARNING: got empty result from action .."];
202 response = [WOResponse alloc];
203 response = [response initWithRequest:_request];
204 [response setStatus:500];
207 /* generate response */
208 response = [[result generateResponse] retain];
211 [(id)result release]; result = nil;
216 RELEASE(pool2); pool2 = nil;
218 response = [response autorelease];
221 response = [app handleException:localException inContext:context];
225 response = [response retain];
230 response = [app handleException:localException inContext:context];
231 response = [response retain];
235 NSAssert(threadDict, @"missing current thread's dictionary ...");
236 [threadDict removeObjectForKey:@"WOContext"];
239 [pool release]; pool = nil;
244 rt = [[NSDateClass date] timeIntervalSince1970] - startHandling;
245 NSLog(@"[da-handler]: handleRequest took %4.3fs.",
246 rt < 0.0 ? -1.0 : rt);
249 return AUTORELEASE(response);
252 @end /* NGXmlRpcRequestHandler */