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 Pulic 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 "WOComponentRequestHandler.h"
23 #include "WORequestHandler+private.h"
24 #include "WOContext+private.h"
25 #include <NGObjWeb/WOApplication.h>
26 #include <NGObjWeb/WORequest.h>
27 #include <NGObjWeb/WOResponse.h>
28 #include <NGObjWeb/WOSession.h>
29 #include <NGObjWeb/WOComponent.h>
32 @interface WOApplication(Privates)
33 - (WOSession *)_initializeSessionInContext:(WOContext *)_ctx;
34 - (void)_setCurrentContext:(WOContext *)_ctx;
37 @interface WORequestHandler(URI)
38 - (BOOL)doesRejectFavicon;
41 @implementation WOComponentRequestHandler
44 return [super version] + 0 /* 2 */;
47 NSAssert2([super version] == 2,
48 @"invalid superclass (%@) version %i !",
49 NSStringFromClass([self superclass]), [super version]);
52 - (WOResponse *)restoreSessionWithID:(NSString *)_sid
53 inContext:(WOContext *)_ctx
55 WOApplication *app = [WOApplication application];
59 // invalid session ID (or no session-ID ?!, which is no error ?) */
60 return [app handleSessionRestorationErrorInContext:_ctx];
63 if ((session = [app restoreSessionWithID:_sid inContext:_ctx]) != nil) {
64 /* awake restored session */
65 [_ctx setSession:session];
66 [session _awakeWithContext:_ctx];
72 return [app handleSessionRestorationErrorInContext:_ctx];
76 The request handler path of a component URI looks like this:
78 sessionID/componentName/contextID/elementID/instance/server
81 - (WOResponse *)handleRequest:(WORequest *)_request {
82 // TODO: this should be integrated into the WORequestHandler default
84 NSString *sessionID = nil;
85 WOApplication *application = nil;
87 WOResponse *response = nil;
88 WOSession *session = nil;
89 WOComponent *component = nil;
91 NSString *handlerPath = nil;
93 if (_request == nil) return nil;
95 if ([self doesRejectFavicon] && [[_request uri] isNotNull]) {
96 // TODO: code copied from WORequestHandler ...
97 if ([@"/favicon.ico" isEqualToString:[_request uri]]) {
98 response = [WOResponse responseWithRequest:_request];
99 [response setStatus:404 /* not found */];
100 [self debugWithFormat:@"rejected favicon request: %@", [_request uri]];
105 application = [WOApplication application];
106 handlerPath = [_request requestHandlerPath];
109 [self logWithFormat:@"[component request handler] path: '%@'", handlerPath];
112 if (![application allowsConcurrentRequestHandling]) {
113 [application lockRequestHandling];
117 context = [WOContext contextWithRequest:_request];
118 [application _setCurrentContext:context];
121 parse handler path (URL)
125 session/context.element-id
127 if ([handlerPath length] > 0) {
128 NSArray *spath = [_request requestHandlerPathArray];
130 if ([spath count] > 1)
131 [context setRequestSenderID:[spath objectAtIndex:1]];
132 if ([spath count] > 0)
133 sessionID = [spath objectAtIndex:0];
136 if ([sessionID length] == 0)
137 sessionID = [application sessionIDFromRequest:_request];
140 [self logWithFormat:@"%s: made context %@ (cid=%@, sn=%@) ..",
141 __PRETTY_FUNCTION__, context, [context contextID], sessionID];
146 /* restore or create session */
147 if ([sessionID isNotNull]) {
148 if ((response = [self restoreSessionWithID:sessionID inContext:context]))
152 Note: this creates a _new_ session if the restoration handler did not
153 return a response! We check that below by comparing the session
156 session = [context session];
159 [self debugWithFormat:@"restored session (id=%@): %@", sessionID, session];
161 if (session && (![sessionID isEqualToString:[session sessionID]])) {
162 [self errorWithFormat:@"session-ids do not match (%@ vs %@)",
163 sessionID, [session sessionID]];
166 if ([session isNotNull]) {
170 only try to restore a page if we still have the same session and if
171 the request contains an element-id (eg if we reconnect to the main
172 URL we do not have an element-id
174 eid = [context currentElementID];
175 if ([sessionID isEqualToString:[session sessionID]] && eid != nil) {
176 /* awake stored page from "old" session */
177 component = [session restorePageForContextID:eid];
179 if (component == nil) {
180 [self logWithFormat:@"could not restore component from session: %@",
182 response = [application handlePageRestorationErrorInContext:context];
185 else /* a new session was created (but no restore-error response ret.) */
186 component = [application pageWithName:nil inContext:context];
188 else if (response == nil) {
189 [[WOApplication application] warnWithFormat:
190 @"got no session restoration error, "
191 @"but missing session!"];
195 /* create new session */
196 session = [application _initializeSessionInContext:context];
197 if ([session isNotNull]) {
198 /* awake created session */
200 component = [application pageWithName:nil inContext:context];
203 response = [application handleSessionCreationErrorInContext:context];
206 if ((session != nil) && (component != nil) && (response == nil)) {
207 WOComponent *newPage = nil;
209 [[session retain] autorelease];
212 NSAssert(application, @"missing application object ..");
213 NSAssert(session, @"missing session object ..");
216 /* set request page in context */
217 [context setPage:component];
219 /* run take-values phase */
220 [application takeValuesFromRequest:_request inContext:context];
222 /* run invoke-action phase */
223 newPage = [application invokeActionForRequest:_request inContext:context];
225 /* process resulting page */
226 if (newPage == nil) {
227 if ((newPage = [context page]) == nil) {
228 newPage = [application pageWithName:nil inContext:context];
229 [context setPage:newPage];
232 else if ([newPage isKindOfClass:[WOComponent class]])
233 [context setPage:newPage];
235 [self debugWithFormat:@"%s: new page: %@", __PRETTY_FUNCTION__, newPage];
237 /* generate response */
239 response = [self generateResponseForComponent:[context page]
241 application:application];
244 [self warnWithFormat:@"%s: did not enter request/response transaction ...",
245 __PRETTY_FUNCTION__];
251 [context sleepComponents];
256 if (session != nil) {
257 if ([context savePageRequired])
258 [session savePage:[context page]];
260 [self debugWithFormat:@"saving session %@", [session sessionID]];
262 if ([session storesIDsInCookies]) {
263 [self debugWithFormat:@"add cookie to session: %@", session];
264 [self addCookiesForSession:session
269 #if 1 // TODO: explain that
270 [application saveSessionForContext:context];
272 [self saveSession:session
274 withResponse:response
275 application:application];
284 [application unlockRequestHandling];
288 [application _setCurrentContext:nil];
292 @end /* WOComponentRequestHandler */