]> err.no Git - sope/blob - sope-appserver/NGXmlRpc/NGXmlRpcRequestHandler.m
INSTALL_ROOT_DIR patch
[sope] / sope-appserver / NGXmlRpc / NGXmlRpcRequestHandler.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
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>
33 #include "common.h"
34
35 static BOOL  perflog = NO;
36 static Class NSDateClass = Nil;
37
38 //#define USE_POOLS 1
39
40 @interface NSObject(RPC2)
41 - (id<WOActionResults>)RPC2Action;
42 @end
43
44 @implementation NGXmlRpcRequestHandler
45
46 + (int)version {
47   return [super version] + 0 /* 2 */;
48 }
49 + (void)initialize {
50   NSAssert2([super version] == 2,
51             @"invalid superclass (%@) version %i !",
52             NSStringFromClass([self superclass]), [super version]);
53
54   NSDateClass = [NSDate class];
55   perflog = [[NSUserDefaults standardUserDefaults]
56                              boolForKey:
57                                @"WOProfileXmlRpcActionRequestHandler"];
58 }
59
60 /*
61   The request handler part of a direct action URI looks like this:
62
63     [actionClass/]actionName[?key=value&key=value&...]
64 */
65
66 - (WOResponse *)_runObject:(NGXmlRpcAction *)_object
67   request:(WORequest *)_req 
68 {
69   WOResponse       *result;
70   XmlRpcMethodCall *call;
71   
72   if (_object == nil) return nil;
73   
74   if (![[_req method] isEqualToString:@"POST"]) {
75     /* only POST is allowed ! */
76     return nil;
77   }
78     
79   call = [(XmlRpcMethodCall *)[XmlRpcMethodCall alloc] initWithRequest:_req];
80   call = [call autorelease];
81     
82   if (call == nil) {
83     NSData *content;
84       
85     content = [_req content];
86     
87     [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
88     [self logWithFormat:@"  content-len: %d", [content length]];
89     [self logWithFormat:@"  encoding:    %d", [_req contentEncoding]];
90     result = nil;
91   }
92   else {
93     [_object awake];
94     result = [[_object performMethodCall:call] generateResponse];
95     [_object sleep];
96   }
97   
98   if (result == nil)
99     return nil;
100   
101   if (![result isKindOfClass:[WOResponse class]]) {
102     /* morph an object result into a XML-RPC response .. */
103     XmlRpcMethodResponse *r;
104     
105     r = [[XmlRpcMethodResponse alloc] initWithResult:result];
106     result = [[[r generateResponse] retain] autorelease];
107     [r release];
108   }
109   
110   return result;
111 }
112
113 - (WOResponse *)handleRequest:(WORequest *)_request {
114   NSTimeInterval    startHandling = 0.0;
115 #if USE_POOLS
116   NSAutoreleasePool *pool = nil;
117 #endif
118   WOApplication *app;
119   NSString      *handlerPath = nil;
120   NSString      *actionClassName;
121   WOResponse    *response   = nil;
122   WOContext     *context    = nil;
123   NSThread      *thread;
124   NSMutableDictionary *threadDict;
125   Class         actionClass = Nil;
126   
127   if (![[_request method] isEqualToString:@"POST"]) {
128     [self logWithFormat:@"only POST requests are valid XML-RPC requests ..."];
129     return nil;
130   }
131   
132   if (perflog)
133     startHandling = [[NSDateClass date] timeIntervalSince1970];
134   
135   thread = [NSThread currentThread];
136   NSAssert(thread, @"missing current thread ...");
137   threadDict = [thread threadDictionary];
138   NSAssert(threadDict, @"missing current thread's dictionary ...");
139   
140   if (_request == nil) return nil;
141   
142   *(&app)             = nil;
143   *(&actionClassName) = nil;
144   
145   app = [WOApplication application];
146   
147   handlerPath = [_request uri];
148   actionClass = [NGXmlRpcAction actionClassForURI:handlerPath];
149   
150   if (actionClass == Nil) {
151     [self logWithFormat:@"found no action class for URI: %@", handlerPath];
152     actionClass = [app defaultActionClassForRequest:_request];
153   }
154   
155 #if DEBUG_XMLRPC_ACTION
156   NSLog(@"[XML-RPC request handler] class=%@ ..",
157         actionClassName);
158 #endif
159   
160 #if USE_POOLS
161   *(&pool) = [[NSAutoreleasePool alloc] init];
162 #endif
163   {
164     /* setup context */
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"];
169     
170     NS_DURING {
171       [app awake];
172       {
173         NGXmlRpcAction      *actionObject = nil;
174         id<WOActionResults> result = nil;
175
176         *(&result) = nil;
177         
178         NS_DURING {
179 #if USE_POOLS
180           NSAutoreleasePool *pool2 = [NSAutoreleasePool new];
181 #endif
182
183           {
184             /* create direct action object */
185             actionObject = [actionClass alloc];
186             actionObject = [actionObject initWithContext:context];
187             actionObject = [actionObject autorelease];
188             
189             if (actionObject == nil) {
190               [app logWithFormat:
191                    @"ERROR: could not create direct action object of class %@",
192                    actionClassName];
193               actionObject = nil;
194             }
195             else {
196               result = [self _runObject:actionObject request:_request];
197               result = [(id)result retain];
198               
199               if (result == nil) {
200                 [self logWithFormat:
201                       @"WARNING: got empty result from action .."];
202                 response = [WOResponse alloc];
203                 response = [response initWithRequest:_request];
204                 [response setStatus:500];
205               }
206               else {
207                 /* generate response */
208                 response = [[result generateResponse] retain];
209               }
210               
211               [(id)result release]; result = nil;
212             }
213           }
214
215 #if USE_POOLS
216           RELEASE(pool2); pool2 = nil;
217 #endif
218           response = [response autorelease];
219         }
220         NS_HANDLER {
221           response = [app handleException:localException inContext:context];
222         }
223         NS_ENDHANDLER;
224         
225         response = [response retain];
226       }
227       [app sleep];
228     }  
229     NS_HANDLER {
230       response = [app handleException:localException inContext:context];
231       response = [response retain];
232     }
233     NS_ENDHANDLER;
234     
235     NSAssert(threadDict, @"missing current thread's dictionary ...");
236     [threadDict removeObjectForKey:@"WOContext"];
237   }
238 #if USE_POOLS
239   [pool release]; pool = nil;
240 #endif
241
242   if (perflog) {
243     NSTimeInterval rt;
244     rt = [[NSDateClass date] timeIntervalSince1970] - startHandling;
245     NSLog(@"[da-handler]: handleRequest took %4.3fs.",
246           rt < 0.0 ? -1.0 : rt);
247   }
248   
249   return AUTORELEASE(response);
250 }
251
252 @end /* NGXmlRpcRequestHandler */