1 // $Id: GSBundleModule.m,v 1.1 2004/06/08 11:15:59 helge Exp $
4 #include "http_config.h"
8 #include "ApacheCmdParms.h"
9 #include "ApacheServer.h"
10 #include "ApacheModule.h"
11 #include "ApacheResourcePool.h"
12 #import <Foundation/Foundation.h>
17 an Apache module gets *unloaded* during the config process !!!
19 This is why we have this helper shared object which is not unloaded :-)
22 @interface NSObject(ModuleClass)
23 + (void)setBundleHandler:(id)_handler;
24 - (module *)apacheModule;
27 static void _ensureObjCEnvironment(void) {
28 #if LIB_FOUNDATION_LIBRARY
29 extern char **environ; /* man 5 environ */
30 static char *argv[2] = { "apache", NULL };
31 [NSProcessInfo initializeWithArguments:argv
37 @interface ApBundleInfo : NSObject
40 ApacheResourcePool *configPool;
45 ApacheModule *bundleHandler;
50 + (NSString *)makeBundlePathAbsolute:(NSString *)_relpath;
51 + (ApBundleInfo *)bundleInfoForPath:(NSString *)_relpath;
56 - (NSString *)bundleModuleClassName;
57 - (Class)bundleModuleClass;
59 - (BOOL)isBundleLoaded;
60 - (BOOL)isApacheModuleInitialized;
64 - (NSString *)setUpWithArgs:(NSString *)_args
65 inPool:(ApacheResourcePool *)_pool;
68 - (void)configureForServer:(ApacheServer *)_server;
72 @implementation ApBundleInfo
74 + (ApBundleInfo *)bundleInfoForPath:(NSString *)_relpath {
75 static NSMutableDictionary *pathToInfo = nil;
79 p = [self makeBundlePathAbsolute:_relpath];
80 if ([p length] == 0) return nil;
82 if (pathToInfo == nil)
83 pathToInfo = [[NSMutableDictionary alloc] initWithCapacity:16];
85 if ((bi = [pathToInfo objectForKey:p]))
88 if ((bi = [[self alloc] initWithPath:p])) {
89 [pathToInfo setObject:bi forKey:p];
94 + (NSString *)makeBundlePathAbsolute:(NSString *)_relpath {
97 if ([_relpath length] == 0) return nil;
99 s = [[[NSProcessInfo processInfo]
101 objectForKey:@"GNUSTEP_SYSTEM_ROOT"];
102 s = [s stringByAppendingPathComponent:@"Library/Bundles"];
103 s = [s stringByAppendingPathComponent:_relpath];
108 - (id)initWithPath:(NSString *)_path {
109 if ([_path length] == 0) {
113 if (![_path isAbsolutePath]) {
114 NSLog(@"bundle path '%@' is not absolute ...", _path);
119 self->bundlePath = [_path copy];
121 [[[_path lastPathComponent] stringByDeletingPathExtension] copy];
122 self->bundle = [[NSBundle bundleWithPath:self->bundlePath] retain];
124 if (self->bundle == nil) {
125 NSLog(@"missing bundle at path %@", self->bundlePath);
134 NSAutoreleasePool *pool;
136 pool = [[NSAutoreleasePool alloc] init];
137 RELEASE(self->configPool);
138 RELEASE(self->bundleHandler);
139 RELEASE(self->bundlePath);
140 RELEASE(self->bundleName);
141 RELEASE(self->bundle);
148 - (BOOL)isBundleLoaded {
149 if (self->bundle == nil) return NO;
150 return self->bundleLoaded;
152 - (BOOL)isApacheModuleInitialized {
153 if (self->apacheModule == NULL) return NO;
154 return self->moduleAdded;
157 - (NSBundle *)bundle {
161 - (NSString *)bundleModuleClassName {
162 return [self->bundleName stringByAppendingString:@"Mod_Module_Class"];
164 - (Class)bundleModuleClass {
165 /* the class which manages the module structure (helper class) */
166 return NSClassFromString([self bundleModuleClassName]);
169 - (Class)bundleHandlerClass {
170 /* the class which represents the apache module itself */
173 if ((c = [self->bundle principalClass]) == Nil)
175 if (![c isKindOfClass:[ApacheModule class]])
183 - (NSString *)setUpWithArgs:(NSString *)_args
184 inPool:(ApacheResourcePool *)_pool
186 NSAutoreleasePool *pool;
189 /* check pre-conditions */
191 if (self->bundle == nil) {
192 return [NSString stringWithFormat:@"%s: missing bundle info",
193 __PRETTY_FUNCTION__];
195 if (self->configPool)
196 return @"config pool is already setup";
197 if (self->bundleHandler)
198 return @"bundle handler is already set up !!!";
200 pool = [[NSAutoreleasePool alloc] init];
203 printf("\nSETUP 0x%p (loaded=%s) ...\n", (unsigned int)self,
204 self->bundleLoaded ? "yes" : "no");
208 /* Step 0: setup resource pool wrapper */
210 self->configPool = RETAIN(_pool);
212 /* Step 1: Load bundle if not done already ... */
214 if (!self->bundleLoaded) {
215 if (![self->bundle load]) {
217 [NSString stringWithFormat:@"couldn't load bundle %@", self->bundle];
219 self->bundleLoaded = YES;
222 if ((modClass = [self bundleModuleClass]) == Nil) {
224 return [NSString stringWithFormat:
225 @"did not find bundle module class (name=%@) ...",
226 [self bundleModuleClassName]];
229 /* Step 2: Initialize bundle handler object ... */
231 self->bundleHandler = [[[self bundleHandlerClass] alloc] init];
232 if (self->bundleHandler == nil) {
234 return [NSString stringWithFormat:
235 @"couldn't initialize bundle handler of class '%@'",
236 [self bundleHandlerClass]];
239 /* Step 3: Remember bundle handler in module-handler class ... */
241 [modClass setBundleHandler:self->bundleHandler];
243 /* Step 4: add Apache C module structure */
245 if ((self->apacheModule = [modClass apacheModule]) == NULL) {
247 return @"did not find apache module structure of bundle";
249 if (self->apacheModule->magic != MODULE_MAGIC_COOKIE) {
251 return [NSString stringWithFormat:
252 @"API module structure of bundle is broken !"];
255 /* Step 5: register module with apache ... */
257 ap_add_loaded_module(self->apacheModule);
258 self->moduleAdded = YES;
260 /* release pool & done */
268 NSAutoreleasePool *pool;
270 pool = [[NSAutoreleasePool alloc] init];
273 printf("TEARDOWN 0x%p ...\n", (unsigned int)self);
277 /* Reverse Step 5: unregister module with apache */
279 if ((self->apacheModule != NULL) && self->moduleAdded)
280 ap_remove_loaded_module(self->apacheModule);
282 self->moduleAdded = NO;
284 /* Reverse Step 4: reset apache module structure */
285 self->apacheModule = NULL;
287 /* Reverse Step 3: reset bundle handler in module-handler class ... */
288 [[self bundleModuleClass] setBundleHandler:nil];
290 /* Reverse Step 2: release bundle handler object ... */
291 RELEASE(self->bundleHandler);
292 self->bundleHandler = nil;
294 /* DO NOT reverse Step 1 ... */
296 /* Reverse Step 0: release config pool proxy */
297 RELEASE(self->configPool); self->configPool = nil;
302 - (void)configureForServer:(ApacheServer *)_server {
303 if (self->apacheModule == NULL) {
304 NSLog(@"missing bundle module ...");
307 if (self->configPool == NULL) {
308 NSLog(@"missing config pool ...");
313 printf("CONFIGURE 0x%p ...\n", (unsigned int)self);
317 ap_single_module_configure([self->configPool handle],
322 @end /* ApBundleInfo */
324 static void unloadModule(void *data) {
327 if ((binfo = (void *)data)) {
332 static int callCount = 0;
334 /* Called when the LoadBundle config directive is found */
335 const char *GSBundleModuleLoadBundleCommand
336 (module *module, cmd_parms *cmd, char *bundlePath)
338 const char *result = NULL;
339 ApacheCmdParms *paras;
340 NSAutoreleasePool *opool;
345 _ensureObjCEnvironment();
348 #if HEAVY_GSBUNDLE_DEBUG
349 printf("%s: #%i module=0x%p pid=%i "
350 "(cmd=0x%p,bp=0x%p) ...\n",
351 __PRETTY_FUNCTION__, callCount, (unsigned int)module, getpid(),
352 (unsigned int)cmd, (unsigned int)bundlePath);
353 fflush(stdout); fflush(stderr);
356 opool = [[NSAutoreleasePool alloc] init];
357 paras = [[ApacheCmdParms alloc] initWithHandle:cmd];
359 /* separate bundle path from bundle args */
361 tmp = [NSString stringWithCString:bundlePath];
362 #if HEAVY_GSBUNDLE_DEBUG
363 printf("%s: %s\n", __PRETTY_FUNCTION__, [[s description] cString]);
364 printf(" paras: %s\n", [[paras description] cString]);
365 printf(" server: %s\n", [[[paras server] description] cString]);
366 fflush(stdout); fflush(stderr);
369 /* separate bundle path and load arguments ... */
373 if ((idx = [tmp indexOfString:@" "]) == NSNotFound) {
378 bp = [tmp substringToIndex:idx];
379 args = [tmp substringFromIndex:(idx + 1)];
383 /* makeup absolute bundle path */
385 if ((bi = [ApBundleInfo bundleInfoForPath:bp]) == nil) {
386 result = ap_pstrcat(cmd->pool, "bundle at '", [bp cString], "' could "
391 if ((tmp = [bi setUpWithArgs:args inPool:[paras pool]])) {
392 result = ap_pstrdup(cmd->pool, [tmp cString]);
396 /* register cleanup */
397 ap_register_cleanup(cmd->pool, bi,
398 (void (*)(void*))unloadModule, ap_null_cleanup);
400 /* run module configuration */
401 [bi configureForServer:[paras server]];