From: helge Date: Wed, 16 Nov 2005 13:26:01 +0000 (+0000) Subject: added mod_objc X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ac47ed9fcaef5fa5c140363a78fa095c5d91797;p=sope added mod_objc git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1175 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- diff --git a/Recycler/ApacheWO/.cvsignore b/Recycler/ApacheWO/.cvsignore new file mode 100644 index 00000000..e0d38cd4 --- /dev/null +++ b/Recycler/ApacheWO/.cvsignore @@ -0,0 +1,4 @@ +*.apache +*_module_structure.m +logs +shared_debug_obj diff --git a/Recycler/ApacheWO/20040608 b/Recycler/ApacheWO/20040608 new file mode 100644 index 00000000..e69de29b diff --git a/Recycler/ApacheWO/AWODirectoryConfig.h b/Recycler/ApacheWO/AWODirectoryConfig.h new file mode 100644 index 00000000..567bffc8 --- /dev/null +++ b/Recycler/ApacheWO/AWODirectoryConfig.h @@ -0,0 +1,27 @@ +// $Id: AWODirectoryConfig.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __AWODirectoryConfig_H__ +#define __AWODirectoryConfig_H__ + +#import + +@class WOApplication, WORequestHandler; +@class ApacheResourcePool, ApacheCmdParms; + +@interface AWODirectoryConfig : NSObject +{ + WOApplication *application; + WORequestHandler *rqHandler; +} + +/* configuration */ + +- (void)setApplication:(WOApplication *)_app; +- (WOApplication *)application; + +- (void)setRequestHandler:(WORequestHandler *)_handler; +- (WORequestHandler *)requestHandler; + +@end + +#endif /* __AWODirectoryConfig_H__ */ diff --git a/Recycler/ApacheWO/AWODirectoryConfig.m b/Recycler/ApacheWO/AWODirectoryConfig.m new file mode 100644 index 00000000..33eb7454 --- /dev/null +++ b/Recycler/ApacheWO/AWODirectoryConfig.m @@ -0,0 +1,137 @@ +// $Id: AWODirectoryConfig.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "AWODirectoryConfig.h" +#include "ApacheWO.h" +#include +#include +#include +#include "common.h" + +@implementation AWODirectoryConfig + +- (id)init { + return self; +} + +- (id)initWithConfig:(AWODirectoryConfig *)_cfg { + if ((self = [self init])) { + self->application = [_cfg->application retain]; + self->rqHandler = [_cfg->rqHandler retain]; + } + return self; +} + +- (id)initWithBaseConfig:(AWODirectoryConfig *)_base + andConfig:(AWODirectoryConfig *)_new +{ + if ((self = [self initWithConfig:_base])) { + if (_new->application) + ASSIGN(self->application, _new->application); + if (_new->rqHandler) + ASSIGN(self->rqHandler, _new->rqHandler); + } + return self; +} + +- (void)dealloc { + RELEASE(self->application); + RELEASE(self->rqHandler); + [super dealloc]; +} ++ (id)mergeBaseConfig:(AWODirectoryConfig *)_base + withNewConfig:(AWODirectoryConfig *)_new +{ + return [[[self alloc] initWithBaseConfig:_base andConfig:_new] autorelease]; +} + +- (NSString *)stringValue { + return [self description]; +} +- (NSString *)description { + NSMutableString *ms; + id tmp; + + ms = [NSMutableString stringWithCapacity:64]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + + if ((tmp = [self application])) + [ms appendFormat:@" app=%@(0x%08X)", [(WOApplication *)tmp name], tmp]; + if ((tmp = [self requestHandler])) + [ms appendFormat:@" rqh=%@", tmp]; + + [ms appendString:@">"]; + return ms; +} + +/* configuration */ + +- (void)setApplication:(WOApplication *)_app { + ASSIGN(self->application, _app); +} +- (WOApplication *)application { + return self->application; +} + +- (void)setRequestHandler:(WORequestHandler *)_handler { + ASSIGN(self->rqHandler, _handler); +} +- (WORequestHandler *)requestHandler { + return self->rqHandler; +} + +/* commands */ + +- (id)SetSxApplication:(NSString *)_key { + WOApplication *app; + + if ((app = [self application])) { + [self logWithFormat:@"application already set !"]; + } + + if ((app = [ApacheWO applicationForKey:_key className:nil]) == nil) { + [self logWithFormat:@"got no application for key '%@'", _key]; + } + else { + [self setApplication:app]; + } + + return nil /* nil means 'no error' */; +} + +- (id)SetSxRequestHandler:(NSString *)_className { + WORequestHandler *rqh; + Class rqhClazz; + + if ((rqh = [self requestHandler])) { + [self logWithFormat:@"requestHandler already set !"]; + } + + if ((rqhClazz = NSClassFromString(_className)) == Nil) { + return [NSString stringWithFormat: + @"did not find request handler for class '%@'", + _className]; + } + + if ((rqh = [[rqhClazz alloc] init]) == nil) { + return [NSString stringWithFormat: + @"could not allocate request handler of class '%@'", + _className]; + } + + [self setRequestHandler:rqh]; + RELEASE(rqh); + + return nil /* nil means 'no error' */; +} + +- (id)LogText:(NSString *)_txt { + if ([_txt length] == 0) + /* return an error text */ + return @"missing echo text !"; + + //[self appendString:_txt]; + + return nil /* nil means 'no error' */; +} + +@end /* AWODirectoryConfig */ diff --git a/Recycler/ApacheWO/AWOServerConfig.h b/Recycler/ApacheWO/AWOServerConfig.h new file mode 100644 index 00000000..bf968e99 --- /dev/null +++ b/Recycler/ApacheWO/AWOServerConfig.h @@ -0,0 +1,22 @@ +// $Id: AWOServerConfig.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __AWOServerConfig_H__ +#define __AWOServerConfig_H__ + +#import + +@class AliasMap; +@class NSMutableDictionary, NSMutableArray; +@class WOApplication, WORequestHandler; +@class ApacheResourcePool, ApacheServer, ApacheCmdParms; + +@interface AWOServerConfig : NSObject +{ +@public + AliasMap *appAlias; + AliasMap *handlerAlias; +} + +@end + +#endif /* __AWOServerConfig_H__ */ diff --git a/Recycler/ApacheWO/AWOServerConfig.m b/Recycler/ApacheWO/AWOServerConfig.m new file mode 100644 index 00000000..9b2f20e6 --- /dev/null +++ b/Recycler/ApacheWO/AWOServerConfig.m @@ -0,0 +1,104 @@ +// $Id: AWOServerConfig.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "AWOServerConfig.h" +#include "AliasMap.h" +#include +#include +#include +#include +#include +#include "common.h" + +@implementation AWOServerConfig + +- (id)initWithServer:(ApacheServer *)_server { + //NSLog(@"%s: init with server: %@", __PRETTY_FUNCTION__, _server); + self->appAlias = [[AliasMap alloc] initWithCapacity:8]; + self->handlerAlias = [[AliasMap alloc] initWithCapacity:8]; + return self; +} + +- (id)initWithConfig:(AWOServerConfig *)_cfg { + if ((self = [self init])) { + self->appAlias = [[AliasMap alloc] initWithAliasMap:_cfg->appAlias]; + self->handlerAlias = + [[AliasMap alloc] initWithAliasMap:_cfg->handlerAlias]; + } + return self; +} + +- (id)initWithBaseConfig:(AWOServerConfig *)_base + andConfig:(AWOServerConfig *)_new +{ + if ((self = [self initWithConfig:_base])) { + [self->appAlias addEntriesFromAliasMap:_new->appAlias]; + [self->handlerAlias addEntriesFromAliasMap:_new->handlerAlias]; + } + return self; +} + +- (void)dealloc { + RELEASE(self->appAlias); + RELEASE(self->handlerAlias); + [super dealloc]; +} + ++ (id)mergeBaseConfig:(AWOServerConfig *)_base + withNewConfig:(AWOServerConfig *)_new +{ + return [[[self alloc] initWithBaseConfig:_base andConfig:_new] autorelease]; +} + +- (NSString *)stringValue { + return [self description]; +} +- (NSString *)description { + NSMutableString *ms; + + ms = [NSMutableString stringWithCapacity:64]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + + [ms appendFormat:@" appAlias=%@", self->appAlias]; + + [ms appendString:@">"]; + return ms; +} + +/* commands */ + +- (id)SxApplicationAlias:(NSString *)_name:(NSString *)_uri { + NSString *tmp; + + if ((tmp = [self->appAlias uriForKey:_name baseURI:@"/"])) { + return [NSString stringWithFormat:@"app %@ already mapped to %@", + _name, tmp]; + } + + //[self logWithFormat:@"aliasing app %@ to %@", _name, _uri]; + + [self->appAlias mapKey:_name toURI:_uri]; + + return nil /* nil means 'no error' */; +} + +- (id)SxHandlerAlias:(NSString *)_handler:(NSString *)_uri { + NSString *tmp; + + if ((tmp = [self->handlerAlias uriForKey:_handler baseURI:@"/"])) { + return [NSString stringWithFormat:@"handler %@ already mapped to %@", + _handler, tmp]; + } + + //[self logWithFormat:@"aliasing handler %@ to %@", _handler, _uri]; + + [self->handlerAlias mapKey:_handler toURI:_uri]; + + return nil /* nil means 'no error' */; +} + +- (id)LoadBundle:(NSString *)_bundleName { + [self logWithFormat:@"should load bundle %@", _bundleName]; + return nil; +} + +@end /* AWOServerConfig */ diff --git a/Recycler/ApacheWO/AliasMap.h b/Recycler/ApacheWO/AliasMap.h new file mode 100644 index 00000000..0cb9225b --- /dev/null +++ b/Recycler/ApacheWO/AliasMap.h @@ -0,0 +1,40 @@ +// $Id: AliasMap.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __AliasMap_H__ +#define __AliasMap_H__ + +#import + +/* + An alias-map maps some kind of key to a URI. During lookups the + URI is processed to find the longest matching prefix. + + Note: a URI may be mapped to only one key, but a key can be mapped + to multiple URIs ! (key<->URI is 1:n) +*/ + +@class NSMutableDictionary, NSMutableArray; + +@interface AliasMap : NSObject < NSCopying > +{ + NSMutableArray *uris; + NSMutableDictionary *uri2key; + NSMutableDictionary *key2uris; +} + +- (id)initWithCapacity:(unsigned)_capacity; +- (id)initWithAliasMap:(AliasMap *)_map; + +/* modification */ + +- (BOOL)mapKey:(id)_key toURI:(NSString *)_uri; +- (BOOL)addEntriesFromAliasMap:(AliasMap *)_map; + +/* query */ + +- (id)keyForURI:(NSString *)_uri; +- (NSString *)uriForKey:(id)_key baseURI:(NSString *)_uri; + +@end + +#endif /* __AliasMap_H__ */ diff --git a/Recycler/ApacheWO/AliasMap.m b/Recycler/ApacheWO/AliasMap.m new file mode 100644 index 00000000..31e16891 --- /dev/null +++ b/Recycler/ApacheWO/AliasMap.m @@ -0,0 +1,139 @@ +// $Id: AliasMap.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "AliasMap.h" +#include "common.h" + +@implementation AliasMap + +- (id)initWithCapacity:(unsigned)_capacity { + self->uri2key = [[NSMutableDictionary alloc] initWithCapacity:_capacity]; + self->key2uris = [[NSMutableDictionary alloc] initWithCapacity:_capacity]; + self->uris = [[NSMutableArray alloc] initWithCapacity:_capacity]; + return self; +} +- (id)initWithAliasMap:(AliasMap *)_map { + self->uri2key = [_map->uri2key mutableCopy]; + self->key2uris = [_map->key2uris mutableCopy]; + self->uris = [_map->uris mutableCopy]; + return self; +} + +- (id)init { + return [self initWithCapacity:16]; +} + +- (void)dealloc { + RELEASE(self->key2uris); + RELEASE(self->uri2key); + RELEASE(self->uris); + [super dealloc]; +} + +/* modification */ + +- (BOOL)mapKey:(id)_key toURI:(NSString *)_uri { + id tmp; + NSMutableArray *kuris; + + if (_uri == nil) return NO; + if (_key == nil) return NO; + + if ((tmp = [self->uri2key objectForKey:_uri])) + /* already mapped !!! */ + return NO; + + [self->uri2key setObject:_key forKey:_uri]; + [self->uris addObject:_uri]; + + if ((kuris = [self->key2uris objectForKey:_key]) == nil) + kuris = [[NSMutableArray alloc] initWithCapacity:4]; + else + kuris = [kuris mutableCopy]; + + [kuris addObject:_uri]; + + [self->key2uris setObject:kuris forKey:_key]; + RELEASE(kuris); + + return YES; +} + +- (BOOL)addEntriesFromAliasMap:(AliasMap *)_map { + [self->uri2key addEntriesFromDictionary:_map->uri2key]; + [self->key2uris addEntriesFromDictionary:_map->key2uris]; + [self->uris addObjectsFromArray:_map->uris]; + return YES; +} + +/* query */ + +- (NSString *)longestMatchingURIForURI:(NSString *)_uri + fromArray:(NSArray *)_baseSet +{ + NSEnumerator *e; + NSString *auri, *longest = nil; + unsigned max = 0, len; + + if ((len = [_uri length]) == 0) + return nil; + + /* foreach registered URI */ + e = [_baseSet objectEnumerator]; + + while ((auri = [e nextObject])) { + unsigned l = [auri length]; + + /* quick precondition: prefix can't be longer than the string .. */ + if (l > len) + continue; + + if ([_uri hasPrefix:auri]) { + if (len == l) /* found an exact match */ + return auri; + + if (l > max) { /* found a new longer uri ... */ + longest = auri; + max = len; + } + } + } + + return longest; +} + +- (id)keyForURI:(NSString *)_uri { + NSString *aliasURI; + + aliasURI = [self longestMatchingURIForURI:_uri fromArray:self->uris]; + if ([aliasURI length] == 0) + return nil; + + return [self->uri2key objectForKey:aliasURI]; +} + +- (NSString *)uriForKey:(id)_key baseURI:(NSString *)_uri { + NSArray *kuris; + NSString *aliasURI; + unsigned kcount; + + kuris = [self->key2uris objectForKey:_key]; + if ((kcount = [kuris count] == 0)) + return nil; + + if (kcount == 1) /* only one possibility */ + aliasURI = [kuris objectAtIndex:0]; + else { + aliasURI = [self longestMatchingURIForURI:_uri fromArray:kuris]; + NSAssert(aliasURI != nil, @"no matching URI in structure ???"); + } + + return aliasURI; +} + +/* copying */ + +- (id)copyWithZone:(NSZone *)_zone { + return [[AliasMap alloc] initWithAliasMap:self]; +} + +@end /* AliasMap */ diff --git a/Recycler/ApacheWO/ApacheCommands.plist b/Recycler/ApacheWO/ApacheCommands.plist new file mode 100644 index 00000000..49569660 --- /dev/null +++ b/Recycler/ApacheWO/ApacheCommands.plist @@ -0,0 +1,46 @@ +{ + DirectoryConfigClass = "AWODirectoryConfig"; + ServerConfigClass = "AWOServerConfig"; + + /* directory config */ + SetSxApplication = { + selector = "SetSxApplication:"; + overrides = ( ACCESS_CONF, OR_OPTIONS ); + argspec = "TAKE1"; + usage = "usage: SetSxApplication "; + }; + SetSxRequestHandler = { + selector = "SetSxRequestHandler:"; + overrides = ( ACCESS_CONF, OR_OPTIONS ); + argspec = "TAKE1"; + usage = "usage: SetSxRequestHandler "; + }; + LogText = { + selector = "LogText:"; + overrides = ( ACCESS_CONF, OR_OPTIONS ); + argspec = "TAKE1"; + usage = "usage: LogText "; + }; + + /* server config */ + + LoadBundle = { + selector = "LoadBundle:"; + overrides = ( RSRC_CONF ); + argspec = "TAKE1"; + usage = "usage: LoadBundle "; + }; + + SxApplicationAlias = { + selector = "SxApplicationAlias::"; + overrides = ( RSRC_CONF ); + argspec = "TAKE2"; + usage = "usage: SxApplicationAlias "; + }; + SxHandlerAlias = { + selector = "SxHandlerAlias::"; + overrides = ( RSRC_CONF ); + argspec = "TAKE2"; + usage = "usage: SxHandlerAlias "; + }; +} diff --git a/Recycler/ApacheWO/ApacheHandlers.plist b/Recycler/ApacheWO/ApacheHandlers.plist new file mode 100644 index 00000000..2b42d6dd --- /dev/null +++ b/Recycler/ApacheWO/ApacheHandlers.plist @@ -0,0 +1,20 @@ +{ + CVSID="$Id: ApacheHandlers.plist,v 1.1 2004/06/08 11:06:00 helge Exp $"; + + /* Note: only lowercase letters are allowed in handler names ! */ + + Name2Selector = { + "objc-echo" = "performObjcEchoRequest:"; + "sx-handler" = "performSxHandlerRequest:config:"; + "wox-page" = "performWoxPageRequest:"; + "sx-alias-handler" = "performSxAliasHandlerRequest:"; + }; + + MimeType2Selector = { + "application/x-httpd-wox" = "performWoxPageRequest:"; + "application/x-httpd-wo" = "handleApplicationXHttpdWoRequest:config:"; + "httpd/unix-directory" = "handleDirectoryRequest:config:"; + "skyrix/request-handler" = "handleSkyrixRqHandler:config:"; +// "*/*" = "handleGenericRequest:config:"; + }; +} diff --git a/Recycler/ApacheWO/ApacheResourceManager.h b/Recycler/ApacheWO/ApacheResourceManager.h new file mode 100644 index 00000000..89ed51e0 --- /dev/null +++ b/Recycler/ApacheWO/ApacheResourceManager.h @@ -0,0 +1,26 @@ +// $Id: ApacheResourceManager.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __ApacheResourceManager_H__ +#define __ApacheResourceManager_H__ + +#include + +@class NSMutableDictionary; +@class ApacheRequest; +@class AWODirectoryConfig; +@class WOComponent; + +@interface ApacheResourceManager : WOResourceManager +{ + ApacheRequest *request; + AWODirectoryConfig *config; + NSMutableDictionary *nameToURL; + WOComponent *component; /* non-retained */ +} + +- (id)initWithApacheRequest:(ApacheRequest *)_rq + config:(AWODirectoryConfig *)_cfg; + +@end + +#endif /* __ApacheResourceManager_H__ */ diff --git a/Recycler/ApacheWO/ApacheResourceManager.m b/Recycler/ApacheWO/ApacheResourceManager.m new file mode 100644 index 00000000..5967f92c --- /dev/null +++ b/Recycler/ApacheWO/ApacheResourceManager.m @@ -0,0 +1,227 @@ +// $Id: ApacheResourceManager.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheResourceManager.h" +#include "AWODirectoryConfig.h" +#include +#include +#include +#include +#include +#include +#include "common.h" + +@interface NSObject(UsedARPrivates) + +- (void)setComponentClass:(Class)_class; + +- (id)_definitionWithName:(NSString *)_name + url:(NSURL *)_url + baseURL:(NSURL *)_burl + frameworkName:(NSString *)_fwname; + +@end + +@implementation ApacheResourceManager + +static NSMutableDictionary *md = nil; + +- (id)initWithURI:(NSString *)_uri { + return self; +} ++ (id)resourceManagerForURI:(NSString *)_uri { + ApacheResourceManager *rm; + NSRange r; + + if ([_uri length] > 1) { + r = [_uri rangeOfString:@"/" options:NSBackwardsSearch]; + if (r.length == 0) { + NSLog(@"%s: strange uri: %@", __PRETTY_FUNCTION__, _uri); + return nil; + } + + _uri = [_uri substringToIndex:(r.location + r.length)]; + } + + if ((rm = [md objectForKey:_uri])) + return rm; + + if ((rm = [[ApacheResourceManager alloc] initWithURI:_uri]) == nil) + return nil; + + if (md == nil) + md = [[NSMutableDictionary alloc] init]; + [md setObject:rm forKey:_uri]; + return AUTORELEASE(rm); +} + +- (id)initWithApacheRequest:(ApacheRequest *)_rq + config:(AWODirectoryConfig *)_cfg +{ + self->request = [_rq retain]; + self->config = [_cfg retain]; + return self; +} +- (void)dealloc { + RELEASE(self->nameToURL); + RELEASE(self->request); + RELEASE(self->config); + [super dealloc]; +} + +/* URLs */ + +- (NSURL *)refererURL { + id rurl; + + if ((rurl = [[self->request headersIn] objectForKey:@"Referer"])) + rurl = [NSURL URLWithString:rurl]; + return rurl; +} + +- (NSURL *)requestURL { + ApacheServer *srv = [self->request server]; + id rurl; + + rurl = [NSString stringWithFormat:@"http://%@:%i%@", + [srv serverHostName], + [srv port], + [self->request uri]]; + rurl = [NSURL URLWithString:rurl]; + return rurl; +} + +/* operations */ + +- (NSURL *)_templateBaseURLForComponentNamed:(id)_name { + ApacheRequest *srq; + NSURL *url = nil; + + if (_name == nil || [_name isEqual:[self->request uri]]) + return [self requestURL]; + + if ([_name isKindOfClass:[NSURL class]]) { + srq = [self->request subRequestLookupURI:[_name uri]]; + } + else { + if ([[_name pathExtension] length] == 0) + _name = [_name stringByAppendingPathExtension:@"wox"]; + + srq = [self->request subRequestLookupURI:_name]; + } + + if ([srq doesFileExist]) { + url = [[[NSURL alloc] initWithString:[srq uri] + relativeToURL:[self requestURL]] + autorelease]; + } + else { + [self logWithFormat:@"file does not exist: %@ (%@)", + [srq filename], [srq fileType]]; + } + return url; +} + +- (id)definitionForComponent:(id)_name + languages:(NSArray *)_languages +{ + id cdef; + NSURL *url, *baseURL; + + if ((baseURL = [self->nameToURL objectForKey:_name]) == nil) { + //[self logWithFormat:@"def for component: %@)", _name]; + + if ((baseURL = [self _templateBaseURLForComponentNamed:_name]) == nil) { + [self logWithFormat:@"did not find template URL for component %@",_name]; + return nil; + } + + if (self->nameToURL == nil) + self->nameToURL = [[NSMutableDictionary alloc] initWithCapacity:16]; + + [self->nameToURL setObject:baseURL forKey:_name]; + } + + /* lookup file for URI */ + + if (baseURL == nil) + return nil; + else if ([baseURL isFileURL]) { + [self logWithFormat:@"baseURL(%@) cannot be a file URL !", baseURL]; +#if DEBUG + exit(1); +#endif + } + else { + ApacheRequest *srq; + NSString *fn; + + fn = [baseURL path]; +#if DEBUG + if ([fn indexOfString:@"INTERNALLY GENERATED"] != NSNotFound) { + [self logWithFormat:@"baseURL(%@) broken !", baseURL]; + exit(2); + } +#endif + + //[self logWithFormat:@"LOOKUP: %@", fn]; + srq = [self->request subRequestLookupURI:[baseURL path] method:@"HEAD"]; + + fn = [srq filename]; + //[self logWithFormat:@"File: %@", fn]; + + url = [[[NSURL alloc] initFileURLWithPath:fn] autorelease]; + + //NSLog(@"mapped:\n base %@\n content %@", baseURL, url); + } + + /* create definition */ + + cdef = [self _definitionWithName:_name + url:url + baseURL:baseURL + frameworkName:nil]; + + [cdef setComponentClass:[WOComponent class]]; + + return cdef; +} + +- (NSString *)urlForResourceNamed:(NSString *)_name + inFramework:(NSString *)_frameworkName + languages:(NSArray *)_languages + request:(WORequest *)_request +{ + NSURL *compURL, *rURL; + + //[self logWithFormat:@"URL for resource named %@", _name]; + + if ((compURL = [self->component baseURL]) == nil) { + compURL = [[[[WOApplication application] context] component] baseURL]; + + if (compURL) { +#if 0 + [self logWithFormat:@"use current component URL: %@", + [compURL absoluteString]]; +#endif + } + } + + if (compURL == nil) { + compURL = [[[WOApplication application] context] baseURL]; + if (self->component) + [self logWithFormat:@"component has no base, using context: %@", + [compURL absoluteString]]; + else + [self logWithFormat:@"using component URL as base: %@", + [compURL absoluteString]]; + } + + //[self logWithFormat:@" relative to %@", [compURL absoluteString]]; + + rURL = [NSURL URLWithString:_name relativeToURL:compURL]; + //[self logWithFormat:@" URL: %@", [rURL absoluteString]]; + + return [rURL absoluteString]; +} + +@end /* ApacheResourceManager */ diff --git a/Recycler/ApacheWO/ApacheWO+Echo.m b/Recycler/ApacheWO/ApacheWO+Echo.m new file mode 100644 index 00000000..d1565234 --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO+Echo.m @@ -0,0 +1,61 @@ +// $Id: ApacheWO+Echo.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheWO.h" +#include "common.h" +#include + +@implementation ApacheWO(EchoHandler) + +- (int)performObjcEchoRequest:(ApacheRequest *)_rq { + NSAutoreleasePool *pool; + id cfg; + NSString *s; + + pool = [[NSAutoreleasePool alloc] init]; + + /* get directory specific info ! */ + cfg = [self configForDirectory:_rq]; + + [self performWoxPageRequest:_rq]; + + NSLog(@"CFG: %@", cfg); + + /* setup header */ + [_rq setContentType:@"text/html"]; + + /* send header to client */ + [_rq sendHttpHeader]; + + /* send body to client */ + [_rq rputs:"

\n"]; + [_rq rputs:"echo !"]; + [_rq rputs:"

\n"]; + + s = [cfg stringValue]; + if ([s length] > 0) + [_rq rputs:[s cString]]; + [_rq rputs:"
\n\n"]; + + [_rq rputs:"URI:
"];
+  [_rq rputs:[[_rq uri] cString]];
+  [_rq rputs:"
\n"]; + + [_rq rputs:"description:
"];
+  [_rq rputs:[[_rq description] cString]];
+  [_rq rputs:"
\n"]; + + [_rq rputs:"headers-in:
"];
+  [_rq rputs:[[[_rq headersIn] description] cString]];
+  [_rq rputs:"
\n"]; + + [_rq rputs:"headers-in-dict:
"];
+  [_rq rputs:[[[[_rq headersIn] asDictionary] description] cString]];
+  [_rq rputs:"
\n"]; + + RELEASE(pool); + + /* say we are done ... */ + return ApacheHandledRequest; +} + +@end /* ApacheWO(EchoHandler) */ diff --git a/Recycler/ApacheWO/ApacheWO+Echo2.m b/Recycler/ApacheWO/ApacheWO+Echo2.m new file mode 100644 index 00000000..97db9ee9 --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO+Echo2.m @@ -0,0 +1,65 @@ +// $Id: ApacheWO+Echo2.m,v 1.1 2004/06/14 15:02:00 helge Exp $ + +#include "ApacheWO.h" +#include "AWODirectoryConfig.h" +#include "ApacheResourceManager.h" +#include "WORequest+Apache.h" +#include "WOResponse+Apache.h" +#include +#include "common.h" + +@implementation ApacheWO(Echo2Handler) + +- (WOResponse *)echoResponseForRequest:(WORequest *)woRequest + apacheRequest:(ApacheRequest *)_rq + config:(id)cfg +{ + WOResponse *woResponse; + + [self logWithFormat:@"generated response was .."]; + woResponse = [[[WOResponse alloc] initWithRequest:woRequest] autorelease]; + + /* construct response */ + + [woResponse setHeader:@"text/html" forKey:@"content-type"]; + [woResponse appendContentString:@"

WOResponse Content

"]; + + [woResponse appendContentHTMLString:[cfg stringValue]]; + [woResponse appendContentString:@"
\n\n"]; + + [woResponse appendContentString:@"URI:
"];
+  [woResponse appendContentHTMLString:[woRequest uri]];
+  [woResponse appendContentString:@"
\n"]; + + [woResponse appendContentString:@"Description:
"];
+  [woResponse appendContentHTMLString:[woRequest description]];
+  [woResponse appendContentString:@"
\n"]; + + [woResponse appendContentString:@"Request Headers:
"];
+  [woResponse appendContentHTMLString:[[woRequest headers] description]];
+  [woResponse appendContentString:@"
\n"]; + + [woResponse appendApacheResponseInfo: + [_rq subRequestLookupURI:@"/docs/subdir/test.wox"]]; + [woResponse appendContentString:@"
"]; + + [woResponse appendApacheResponseInfo: + [_rq subRequestLookupFile:@"test.wox"]]; + [woResponse appendContentString:@"
"]; + + [woResponse appendApacheResponseInfo: + [_rq subRequestLookupURI:@"/docs/subdir/non_existent.wox"]]; + [woResponse appendContentString:@"
"]; + + [woResponse appendApacheResponseInfo: + [_rq subRequestLookupURI:@"/docs/subdir/"]]; + [woResponse appendContentString:@"
"]; + + [woResponse appendApacheResponseInfo: + [_rq subRequestLookupURI:@"/docs/bigimg.gif"]]; + [woResponse appendContentString:@"
"]; + + return woResponse; +} + +@end /* ApacheWO(Echo2Handler) */ diff --git a/Recycler/ApacheWO/ApacheWO+RequestHandler.m b/Recycler/ApacheWO/ApacheWO+RequestHandler.m new file mode 100644 index 00000000..3c84f8b9 --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO+RequestHandler.m @@ -0,0 +1,83 @@ +// $Id: ApacheWO+RequestHandler.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheWO.h" +#include "AWODirectoryConfig.h" +#include "ApacheResourceManager.h" +#include "WORequest+Apache.h" +#include "WOResponse+Apache.h" +#include "common.h" +#include +#include +#include + +/* + implements a WORequestHandler "dispatcher" + + All WORequestHandler classes are registered in the ApacheHandlers.plist + with the single dispatchRequest: selector. This method creates an object + of the request handler class and let it dispatch the request. +*/ + +@implementation ApacheWO(RequestHandler) + +- (int)dispatchRequest:(ApacheRequest *)_rq + usingHandlerNamed:(NSString *)_hname + inApplication:(WOApplication *)_app +{ + WORequestHandler *handler; + WORequest *woRequest; + WOResponse *woResponse; + int result; + + if ((handler = [_app requestHandlerForKey:_hname]) == nil) { + [self logWithFormat:@"did not find request handler for key '%@'", + _hname]; + return ApacheDeclineRequest; + } + + woRequest = [[[WORequest alloc] initWithApacheRequest:_rq] autorelease]; + + woResponse = [_app dispatchRequest:woRequest usingHandler:handler]; + + /* send response */ + + if (woResponse) + result = [woResponse sendResponseUsingApacheRequest:_rq]; + else + result = 500; + + return result; +} + +- (int)dispatchRequestHandler:(ApacheRequest *)_rq { + NSAutoreleasePool *pool; + AWODirectoryConfig *cfg; + WOApplication *app; + int result; + + if (_rq == NULL) + return ApacheDeclineRequest; + + pool = [[NSAutoreleasePool alloc] init]; + + /* get directory specific info (app, request-handler) ! */ + + cfg = [self configForDirectory:_rq]; + + if ((app = [cfg application]) == nil) { + [self logWithFormat:@"missing app .."]; + goto done; + } + + result = [self dispatchRequest:_rq + usingHandlerNamed:[_rq handler] + inApplication:app]; + + done: + RELEASE(pool); + + /* say we are done ... */ + return result; +} + +@end /* ApacheWO(WoxPageHandler) */ diff --git a/Recycler/ApacheWO/ApacheWO+hooks.m b/Recycler/ApacheWO/ApacheWO+hooks.m new file mode 100644 index 00000000..7072cf9c --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO+hooks.m @@ -0,0 +1,76 @@ +// $Id: ApacheWO+hooks.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheWO.h" +#include "AliasMap.h" +#include "AWOServerConfig.h" +#include +#include +#include "common.h" + +@implementation ApacheWO(Hooks) + +- (int)handleTranslationForRequest:(ApacheRequest *)_rq { + AWOServerConfig *cfg; + NSString *uri = [_rq uri]; + NSString *app, *rqh; + + cfg = [self configForServer:_rq]; + + //[self logWithFormat:@"translate URI '%@' (cfg=%@) ...", uri, cfg]; + + /* check handler aliases */ + + if ((rqh = [cfg->handlerAlias keyForURI:uri])) { + NSString *prefix; + + prefix = [cfg->handlerAlias uriForKey:rqh baseURI:uri]; + //[self logWithFormat:@"found handler: %@ (prefix=%@)", rqh, prefix]; + + [_rq setFilename:prefix]; + [_rq setPathInfo:[uri substringFromIndex:[prefix length]]]; + [_rq setHandler:@"sx-alias-handler"]; + return ApacheHandledRequest; + } + + /* check app aliases */ + + if ((app = [cfg->appAlias keyForURI:uri])) { + NSString *prefix; + + prefix = [cfg->appAlias uriForKey:app baseURI:uri]; + [self logWithFormat:@"found app: %@ (prefix=%@)", app, prefix]; + + [_rq setFilename:prefix]; + [_rq setPathInfo:[uri substringFromIndex:[prefix length]]]; + [_rq setHandler:@"sx-application"]; + return ApacheHandledRequest; + } + + return ApacheDeclineRequest; +} + +#if 0 +- (int)checkUserIdFromRequest:(ApacheRequest *)_req { + [self logWithFormat:@"check uid for URI '%@' ...", [_req uri]]; + return ApacheDeclineRequest; +} +#endif + +- (int)checkTypeForRequest:(ApacheRequest *)_req { + /* do not process .wo directories as simple directories .. */ + + //[self logWithFormat:@"check type for URI '%@' ...", [_req uri]]; + + if ([_req isDirectory]) { + NSString *fext; + + fext = [[[_req filename] lastPathComponent] pathExtension]; + if ([fext isEqualToString:@"wo"]) { + [_req setContentType:@"application/x-httpd-wo"]; + return ApacheHandledRequest; + } + } + return ApacheDeclineRequest; +} + +@end /* ApacheWO(Hooks) */ diff --git a/Recycler/ApacheWO/ApacheWO+woxpage.m b/Recycler/ApacheWO/ApacheWO+woxpage.m new file mode 100644 index 00000000..a106a7dd --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO+woxpage.m @@ -0,0 +1,144 @@ +// $Id: ApacheWO+woxpage.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheWO.h" +#include "AliasMap.h" +#include "WORequestHandler+Apache.h" +#include "AWODirectoryConfig.h" +#include "AWOServerConfig.h" +#include "ApacheWOTransaction.h" +#include "ApacheResourceManager.h" +#include "WORequest+Apache.h" +#include "WOResponse+Apache.h" +#include "common.h" +#include +#include +#include + +@interface WORequest(UsedPrivatesApache) +- (void)setRequestHandlerPath:(NSString *)_path; +- (ApacheRequest *)apacheRequest; +@end + +@interface ApacheWO(EchoResponseE) +- (WOResponse *)echoResponseForRequest:(WORequest *)woRequest + apacheRequest:(ApacheRequest *)_rq + config:(id)cfg; +@end + +@implementation ApacheWO(WoxPageHandler) + +- (int)performSxApplicationRequest:(ApacheRequest *)_rq { + AWOServerConfig *cfg; + NSString *uri = [_rq uri]; + NSString *appKey; + WOApplication *app; + WORequest *woRequest; + WOResponse *woResponse; + int result; + + if (uri == nil) + return ApacheDeclineRequest; + + woRequest = [[[WORequest alloc] initWithApacheRequest:_rq] autorelease]; + + cfg = [self configForServer:_rq]; + appKey = [cfg->appAlias keyForURI:uri]; + app = [ApacheWO applicationForKey:appKey className:nil]; + + [self logWithFormat:@"performSxApplicationRequest on app %@ ...", app]; + woResponse = [app dispatchRequest:woRequest]; + + /* send response */ + + if (woResponse) + result = [woResponse sendResponseUsingApacheRequest:_rq]; + else + result = 500; + + return result; +} + +- (int)performSxHandlerRequest:(ApacheRequest *)_rq + config:(AWODirectoryConfig *)cfg +{ + WORequestHandler *handler; + + if ((handler = [cfg requestHandler]) == nil) { + handler = [[cfg application] defaultRequestHandler]; + [self logWithFormat:@"using default request handler ..."]; + } + + return [[self currentWOTransaction] dispatchUsingHandler:handler]; +} + +- (int)performSxAliasHandlerRequest:(ApacheRequest *)_rq { + ApacheWOTransaction *tx; + WORequestHandler *handler; + NSString *key; + + tx = [self currentWOTransaction]; + key = [tx->serverConfig->handlerAlias keyForURI:[_rq uri]]; + handler = [[tx application] requestHandlerForKey:key]; + + return [tx dispatchUsingHandler:handler]; +} + +- (int)performWoxPageRequest:(ApacheRequest *)_rq { + WORequestHandler *rh; + WORequest *woRq; + + rh = [[[NSClassFromString(@"WOPageRequestHandler") alloc] init] autorelease]; + if (rh == nil) + [self logWithFormat:@"couldn't allocate page request handler .."]; + + /* fill request special vars */ + woRq = [[self currentWOTransaction] request]; + [woRq setHeader: [woRq uri] forKey:@"x-httpd-pagename"]; + [woRq setRequestHandlerPath:[[woRq uri] lastPathComponent]]; + + return [[self currentWOTransaction] dispatchUsingHandler:rh]; +} + +- (int)handleApplicationXHttpdWoRequest:(ApacheRequest *)_rq config:_cfg { + NSString *uri = [_rq uri]; + + [self logWithFormat:@"handleApplicationXHttpdWoxRequest (uri=%@) ...",uri]; + + /* remove the slash of .wo directories, deny access to contents .. */ + if ([uri hasSuffix:@".wo/"]) { + uri = [uri substringToIndex:([uri length] - 1)]; + [self logWithFormat:@"redirect to %@...", uri]; + + [[_rq headersOut] setObject:uri forKey:@"location"]; + [_rq setStatus:302]; + [_rq sendHttpHeader]; + return ApacheHandledRequest; /* redirect */ + } + + return [self performWoxPageRequest:_rq]; +} + +- (int)handleSkyrixRqHandler:(ApacheRequest *)_rq config:(id)_cfg { + NSDictionary *plist; + WORequestHandler *rh; + + plist = [NSDictionary dictionaryWithContentsOfFile:[_rq filename]]; + [self logWithFormat:@"plist: %@", plist]; + + if ((rh = [WORequestHandler requestHandlerForConfig:plist]) == nil) + return ApacheDeclineRequest; + + return [[self currentWOTransaction] dispatchUsingHandler:rh]; +} + +- (int)handleDirectoryRequest:(ApacheRequest *)_rq config:(id)_cfg { + [self logWithFormat:@"check directory: %@", [_rq filename]]; + return ApacheDeclineRequest; +} +- (int)handleGenericRequest:(ApacheRequest *)_rq config:(id)_cfg { + [self logWithFormat:@"(generic) check file: %@ (%@)", + [_rq filename], [_rq contentType]]; + return ApacheDeclineRequest; +} + +@end /* ApacheWO(WoxPageHandler) */ diff --git a/Recycler/ApacheWO/ApacheWO.h b/Recycler/ApacheWO/ApacheWO.h new file mode 100644 index 00000000..5ddbb85a --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO.h @@ -0,0 +1,30 @@ +// $Id: ApacheWO.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __ApacheWOMod_H__ +#define __ApacheWOMod_H__ + +#include + +@class NSString, NSMutableArray; +@class WOApplication; +@class ApacheWOTransaction; + +@interface ApacheWO : ApacheModule +{ + NSMutableArray *woTxStack; +} + +/* WO transactions */ + +- (ApacheWOTransaction *)currentWOTransaction; + +/* application management */ + ++ (WOApplication *)applicationForKey:(NSString *)_key + className:(NSString *)_className; + +@end + +#include "ApacheWOTransaction.h" + +#endif /* __ApacheWOMod_H__ */ diff --git a/Recycler/ApacheWO/ApacheWO.m b/Recycler/ApacheWO/ApacheWO.m new file mode 100644 index 00000000..9e69d6bd --- /dev/null +++ b/Recycler/ApacheWO/ApacheWO.m @@ -0,0 +1,115 @@ +// $Id: ApacheWO.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheWO.h" +#include "common.h" +#include +#include +#include + +@interface WOApplication(UsedPrivates) +- (id)initWithName:(NSString *)_name; +@end + +@implementation ApacheWO + +- (id)init { + if ((self = [super init])) { + self->woTxStack = [[NSMutableArray alloc] initWithCapacity:4]; + } + return self; +} +- (void)dealloc { + RELEASE(self->woTxStack); + [super dealloc]; +} + +/* transactions */ + +- (ApacheWOTransaction *)currentWOTransaction { + if ([self->woTxStack count] == 0) return nil; + return [self->woTxStack lastObject]; +} + +- (BOOL)willDispatchRequest:(ApacheRequest *)_rq { + /* this is called before a handler is invoked */ + ApacheWOTransaction *tx; + + if (![super willDispatchRequest:_rq]) + return NO; + + tx = [[ApacheWOTransaction alloc] + initWithApacheRequest:_rq + config:[self configForDirectory:_rq] + serverConfig:[self configForServer:_rq]]; + if (tx == nil) + return NO; + + //[self logWithFormat:@"pushing WO transaction: %@", tx]; + + [self->woTxStack addObject:tx]; + + [tx activate]; + + RELEASE(tx); + return YES; +} + +- (void)didDispatchRequest:(ApacheRequest *)_rq { + /* this is called after a handler was invoked */ + unsigned idx; + ApacheWOTransaction *tx; + + if ((idx = [self->woTxStack count]) == 0) { + [self logWithFormat: + @"tx stack broken, tried to pop tx from empty stack !"]; + return; + } + idx--; + + tx = RETAIN([self->woTxStack objectAtIndex:idx]); + //[self logWithFormat:@"popping WO transaction: %@.", tx]; + [tx deactivate]; + [self->woTxStack removeObjectAtIndex:idx]; + RELEASE(tx); +} + +/* application management */ + ++ (WOApplication *)applicationForKey:(NSString *)_key + className:(NSString *)_className +{ + static NSMutableDictionary *keyToApp = nil; // THREAD + WOApplication *app; + Class clazz; + + if (keyToApp == nil) + keyToApp = [[NSMutableDictionary alloc] initWithCapacity:16]; + + if ((app = [keyToApp objectForKey:_key])) + return app; + + if (_className == nil) _className = @"WOApplication"; + if ((clazz = NSClassFromString(_className)) == nil) { + [self logWithFormat:@"did not find class named '%@'", _className]; + return nil; + } + + if ((app = [[clazz alloc] initWithName:_key]) == nil) { + [self logWithFormat: + @"couldn't create instance for application of class %@", + clazz]; + return nil; + } + + /* resource managers are request dependend with our Apache module :-) */ + [app setResourceManager:nil]; + + //[self logWithFormat:@"added application %@ for key %@", app, _key]; + + [keyToApp setObject:app forKey:_key]; + RELEASE(app); + + return app; +} + +@end /* ApacheWO */ diff --git a/Recycler/ApacheWO/ApacheWOTransaction.h b/Recycler/ApacheWO/ApacheWOTransaction.h new file mode 100644 index 00000000..d8d62994 --- /dev/null +++ b/Recycler/ApacheWO/ApacheWOTransaction.h @@ -0,0 +1,47 @@ +// $Id: ApacheWOTransaction.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __ApacheWOTransaction_H__ +#define __ApacheWOTransaction_H__ + +#import + +@class ApacheRequest; +@class WORequest, WOResponse, WOApplication, WORequestHandler; +@class AWODirectoryConfig, AWOServerConfig; +@class ApacheResourceManager; + +@interface ApacheWOTransaction : NSObject +{ +@public + ApacheRequest *request; + WORequest *woRequest; + WOResponse *woResponse; + AWODirectoryConfig *config; + AWOServerConfig *serverConfig; + WOApplication *application; + ApacheResourceManager *resourceManager; +} + +- (id)initWithApacheRequest:(ApacheRequest *)_rq + config:(AWODirectoryConfig *)_cfg + serverConfig:(AWOServerConfig *)_srvcfg; + +/* accessors */ + +- (WORequest *)request; +- (WOResponse *)response; +- (WOApplication *)application; +- (ApacheRequest *)apacheRequest; + +/* activation */ + +- (void)activate; +- (void)deactivate; + +/* dispatch */ + +- (int)dispatchUsingHandler:(WORequestHandler *)_handler; + +@end + +#endif /* __ApacheWOTransaction_H__ */ diff --git a/Recycler/ApacheWO/ApacheWOTransaction.m b/Recycler/ApacheWO/ApacheWOTransaction.m new file mode 100644 index 00000000..1f8b2341 --- /dev/null +++ b/Recycler/ApacheWO/ApacheWOTransaction.m @@ -0,0 +1,116 @@ +// $Id: ApacheWOTransaction.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "ApacheWOTransaction.h" +#include "common.h" + +#include "AWODirectoryConfig.h" +#include "AWOServerConfig.h" +#include "ApacheResourceManager.h" +#include "WORequest+Apache.h" +#include "WOResponse+Apache.h" +#include +#include +#include +#include + +@implementation ApacheWOTransaction + +- (id)initWithApacheRequest:(ApacheRequest *)_rq + config:(AWODirectoryConfig *)_cfg + serverConfig:(AWOServerConfig *)_srvcfg +{ + if (_rq == nil) { + RELEASE(self); + return nil; + } + self->config = RETAIN(_cfg); + self->serverConfig = RETAIN(_srvcfg); + self->request = RETAIN(_rq); + + if ((self->woRequest = [[WORequest alloc] initWithApacheRequest:_rq])==nil) { + NSLog(@"%s: could not create WO request ...", __PRETTY_FUNCTION__); + RELEASE(self); + return nil; + } + + if ((self->application = [[_cfg application] retain]) == nil) { + NSLog(@"%s: no app is configured ...", __PRETTY_FUNCTION__); + RELEASE(self); + return nil; + } + + self->resourceManager = + [[ApacheResourceManager alloc] initWithApacheRequest:_rq config:_cfg]; + + if (self->resourceManager == nil) { + NSLog(@"%s: could not create resource manager ...", __PRETTY_FUNCTION__); + RELEASE(self); + return nil; + } + + return self; +} + +- (void)dealloc { + RELEASE(self->resourceManager); + RELEASE(self->woRequest); + RELEASE(self->woResponse); + RELEASE(self->application); + RELEASE(self->serverConfig); + RELEASE(self->config); + RELEASE(self->request); + [super dealloc]; +} + +/* accessors */ + +- (WOApplication *)application { + return [self->config application]; +} +- (WORequest *)request { + return self->woRequest; +} +- (WOResponse *)response { + return self->woResponse; +} + +- (ApacheRequest *)apacheRequest { + return self->request; +} + +/* activation */ + +- (void)activate { + [self->application activateApplication]; + // should use stack ?? + [self->application setResourceManager:self->resourceManager]; +} +- (void)deactivate { + [self->application setResourceManager:nil]; + [self->application deactivateApplication]; +} + +/* dispatch */ + +- (int)dispatchUsingHandler:(WORequestHandler *)_handler { + WOResponse *response; + + response = [self->application + dispatchRequest:self->woRequest + usingHandler:_handler]; + return [response sendResponseUsingApacheRequest:self->request]; +} + +/* description */ + +- (NSString *)description { + NSMutableString *ms; + + ms = [NSMutableString stringWithCapacity:64]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + [ms appendFormat:@" uri=%@", [[self request] uri]]; + [ms appendString:@">"]; + return ms; +} + +@end /* ApacheWOTransaction */ diff --git a/Recycler/ApacheWO/ChangeLog b/Recycler/ApacheWO/ChangeLog new file mode 100644 index 00000000..0c05d7e8 --- /dev/null +++ b/Recycler/ApacheWO/ChangeLog @@ -0,0 +1,5 @@ +2004-06-14 Helge Hess + + * created ChangeLog + + diff --git a/Recycler/ApacheWO/GNUmakefile b/Recycler/ApacheWO/GNUmakefile new file mode 100644 index 00000000..d38c8ef7 --- /dev/null +++ b/Recycler/ApacheWO/GNUmakefile @@ -0,0 +1,46 @@ +# $Id: GNUmakefile,v 1.2 2004/06/14 15:02:00 helge Exp $ + +include $(GNUSTEP_MAKEFILES)/common.make + +BUNDLE_NAME = ApacheWO + +ApacheWO_PRINCIPAL_CLASS = ApacheWO +BUNDLE_EXTENSION = .apache + +# NOTE: Ordering seems to be important !!! (sometimes the ObjC runtime +# doesn't find all categories ?!) +ApacheWO_OBJC_FILES += \ + ApacheWO+Echo.m \ + ApacheWO+woxpage.m \ + ApacheWO+Echo2.m \ + ApacheWO+hooks.m \ + ApacheWO+RequestHandler.m \ + ApacheWO.m \ + AWODirectoryConfig.m \ + AWOServerConfig.m \ + WORequest+Apache.m \ + WOResponse+Apache.m \ + WOComponent+Apache.m \ + WORequestHandler+Apache.m \ + ApacheResourceManager.m \ + AliasMap.m \ + ApacheWOTransaction.m \ + +ApacheWO_BUNDLE_LIBS += \ + -lApacheAPI \ + -lNGExtensions \ + -lNGObjWeb \ + +ApacheWO_RESOURCE_FILES = ApacheCommands.plist ApacheHandlers.plist + +# auto info + +ApacheWO_OBJC_FILES += ApacheWO_module_structure.m + +ApacheWO_module_structure.m : + $(GNUSTEP_MAKEFILES)/genApacheModule.sh ApacheWO $@ + +after-clean :: + rm -f ApacheWO_module_structure.m + +include $(GNUSTEP_MAKEFILES)/bundle.make diff --git a/Recycler/ApacheWO/README b/Recycler/ApacheWO/README new file mode 100644 index 00000000..3e9fb93a --- /dev/null +++ b/Recycler/ApacheWO/README @@ -0,0 +1,17 @@ +last change: +20040608? + +How to start +============ + +First you need to tweek httpd.conf to reflect you pathes ... +Important: you probably need to *install* the bundle before it works, +Apache doesn't search for the bundle in the current directory ... + +The easiest way to start it is to invoke: + +# httpd -X -f $PWD/httpd.conf + +The -X option starts Apache in single-process mode (no children are +forked) and the -f specifies the local server config file. Note that +the server config file needs to be specified as an absolute path. diff --git a/Recycler/ApacheWO/TestApp/GNUmakefile b/Recycler/ApacheWO/TestApp/GNUmakefile new file mode 100644 index 00000000..5cc22416 --- /dev/null +++ b/Recycler/ApacheWO/TestApp/GNUmakefile @@ -0,0 +1,12 @@ +# $Id: GNUmakefile,v 1.1 2004/06/14 14:59:26 helge Exp $ + +include $(GNUSTEP_MAKEFILES)/common.make + +BUNDLE_NAME = TestApp + +TestApp_OBJC_FILES = \ + TestApp.m \ + +TestApp_RESOURCE_FILES = \ + +include $(GNUSTEP_MAKEFILES)/bundle.make diff --git a/Recycler/ApacheWO/TestApp/TestApp.m b/Recycler/ApacheWO/TestApp/TestApp.m new file mode 100644 index 00000000..2b7fbb76 --- /dev/null +++ b/Recycler/ApacheWO/TestApp/TestApp.m @@ -0,0 +1,9 @@ +// $Id: TestApp.m,v 1.1 2004/06/14 14:59:26 helge Exp $ + +#include + +@interface TestApp : WOApplication +@end + +@implementation TestApp +@end diff --git a/Recycler/ApacheWO/WOComponent+Apache.m b/Recycler/ApacheWO/WOComponent+Apache.m new file mode 100644 index 00000000..149e813f --- /dev/null +++ b/Recycler/ApacheWO/WOComponent+Apache.m @@ -0,0 +1,35 @@ +// $Id: WOComponent+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include +#include +#include +#include +#include "common.h" + +@interface WOContext(Apache) +- (ApacheRequest *)apacheRequest; +@end + +@implementation WOContext(Apache) + +- (ApacheRequest *)apacheRequest { + return [[[self request] userInfo] objectForKey:@"ApacheRequest"]; +} + +- (id)_jsprop_apacheRequest { + return [self apacheRequest]; +} + +@end /* WOContext(Apache) */ + +@implementation WOComponent(Apache) + +- (ApacheRequest *)apacheRequest { + return [[self context] apacheRequest]; +} + +- (id)_jsprop_apacheRequest { + return [self apacheRequest]; +} + +@end /* WOComponent(Apache) */ diff --git a/Recycler/ApacheWO/WORequest+Apache.h b/Recycler/ApacheWO/WORequest+Apache.h new file mode 100644 index 00000000..91c6407a --- /dev/null +++ b/Recycler/ApacheWO/WORequest+Apache.h @@ -0,0 +1,16 @@ +// $Id: WORequest+Apache.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __WORequest_Apache_H__ +#define __WORequest_Apache_H__ + +#include + +@class ApacheRequest; + +@interface WORequest(Apache) + +- (id)initWithApacheRequest:(ApacheRequest *)_rq; + +@end /* WORequest(Apache) */ + +#endif /* __WORequest_Apache_H__ */ diff --git a/Recycler/ApacheWO/WORequest+Apache.m b/Recycler/ApacheWO/WORequest+Apache.m new file mode 100644 index 00000000..ef8c5380 --- /dev/null +++ b/Recycler/ApacheWO/WORequest+Apache.m @@ -0,0 +1,117 @@ +// $Id: WORequest+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "WORequest+Apache.h" +#include +#include +#include +#include "common.h" + +@interface WORequest(ApachePrivates) + +- (NSData *)readDataFromApacheRequest:(ApacheRequest *)_rq; + +@end + +@implementation WORequest(Apache) + +- (id)initWithApacheRequest:(ApacheRequest *)_rq { + NSMutableDictionary *headers; + NSAutoreleasePool *pool; + NSString *httpVersion = nil; + NSData *contentData; + NSDictionary *ui; + NGHashMap *form; + + if (_rq == nil) { + RELEASE(self); + return nil; + } + + pool = [[NSAutoreleasePool alloc] init]; + headers = [[NSMutableDictionary alloc] initWithCapacity:32]; + + /* the values need to be parsed ! */ + { + ApacheTable *hin; + NSEnumerator *keys; + NSString *key; + + hin = [_rq headersIn]; + keys = [hin keyEnumerator]; + while ((key = [keys nextObject])) { + NSString *value; + + if ((value = [hin objectForKey:key]) == nil) { + [self logWithFormat:@"got no value for key '%@' ..", key]; + continue; + } + + /* NGObjWeb expects all keys to be lowercase .. */ + key = [key lowercaseString]; + [headers setObject:value forKey:key]; + } + } + + /* setup "special" headers */ + { + ApacheConnection *con = [_rq connection]; + NSString *tmp; + + if ((tmp = [headers objectForKey:@"host"])) { + tmp = [@"http://" stringByAppendingString:tmp]; + [headers setObject:tmp forKey:@"x-webobjects-server-url"]; + } + if ([(tmp = [con remoteHost]) length] > 0) + [headers setObject:tmp forKey:@"x-webobjects-remote-host"]; + if ([(tmp = [con user]) length] > 0) + [headers setObject:tmp forKey:@"x-webobjects-remote-user"]; + if ([(tmp = [con authorizationType]) length] > 0) + [headers setObject:tmp forKey:@"x-webobjects-auth-type"]; + } + + /* content, this is to be done ... (libapr ?, hm) */ + contentData = [self readDataFromApacheRequest:_rq]; + + /* userinfo */ + + ui = [NSDictionary dictionaryWithObject:_rq forKey:@"ApacheRequest"]; + + /* form values */ + + { + const char *cstr = [[_rq unparsedURI] cString]; + const char *pos = index(cstr, '?'); + + if (pos) { + pos++; + form = NGDecodeUrlFormParameters(pos, strlen(pos)); + } + else + form = nil; + } + + /* construct */ + + self = [self initWithMethod:[_rq method] + uri:[_rq uri] + httpVersion:httpVersion + headers:headers + content:contentData + userInfo:ui]; + ASSIGN(self->formContent, form); + + RELEASE(headers); + RELEASE(pool); + return self; +} + +- (NSData *)readDataFromApacheRequest:(ApacheRequest *)_rq { +#warning read request content if available ... + return nil; +} + +- (ApacheRequest *)apacheRequest { + return [[self userInfo] objectForKey:@"ApacheRequest"]; +} + +@end /* WORequest(Apache) */ diff --git a/Recycler/ApacheWO/WORequestHandler+Apache.h b/Recycler/ApacheWO/WORequestHandler+Apache.h new file mode 100644 index 00000000..2af89dc8 --- /dev/null +++ b/Recycler/ApacheWO/WORequestHandler+Apache.h @@ -0,0 +1,17 @@ +// $Id: WORequestHandler+Apache.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __WORequestHandler_ApacheExt_H__ +#define __WORequestHandler_ApacheExt_H__ + +#include + +@class NSDictionary; + +@interface WORequestHandler(ApacheExt) + ++ (WORequestHandler *)requestHandlerForConfig:(NSDictionary *)_plist; +- (id)initWithConfig:(NSDictionary *)_cfg; + +@end + +#endif /* __WORequestHandler_ApacheExt_H__ */ diff --git a/Recycler/ApacheWO/WORequestHandler+Apache.m b/Recycler/ApacheWO/WORequestHandler+Apache.m new file mode 100644 index 00000000..0c9096bf --- /dev/null +++ b/Recycler/ApacheWO/WORequestHandler+Apache.m @@ -0,0 +1,28 @@ +// $Id: WORequestHandler+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "WORequestHandler+Apache.h" +#include "common.h" + +@implementation WORequestHandler(ApacheExt) + +- (id)initWithConfig:(NSDictionary *)_cfg { + return [self init]; +} + ++ (WORequestHandler *)requestHandlerForConfig:(NSDictionary *)_plist { + NSString *className; + Class clazz; + + className = [_plist objectForKey:@"class"]; + if ([className length] == 0) + return nil; + + if ((clazz = NSClassFromString(className)) == Nil) { + [self logWithFormat:@"did not find request handler class %@", className]; + return nil; + } + + return [[[clazz alloc] initWithConfig:_plist] autorelease]; +} + +@end /* WORequestHandler(ApacheExt) */ diff --git a/Recycler/ApacheWO/WOResponse+Apache.h b/Recycler/ApacheWO/WOResponse+Apache.h new file mode 100644 index 00000000..28eda798 --- /dev/null +++ b/Recycler/ApacheWO/WOResponse+Apache.h @@ -0,0 +1,20 @@ +// $Id: WOResponse+Apache.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#ifndef __WOResponse_Apache_H__ +#define __WOResponse_Apache_H__ + +#include + +@class ApacheRequest; + +@interface WOResponse(Apache) + +- (int)sendResponseUsingApacheRequest:(ApacheRequest *)_rq; + +@end /* WOResponse(Apache) */ + +@interface WOResponse(ApacheInfo) +- (void)appendApacheResponseInfo:(ApacheRequest *)_request; +@end + +#endif /* __WOResponse_Apache_H__ */ diff --git a/Recycler/ApacheWO/WOResponse+Apache.m b/Recycler/ApacheWO/WOResponse+Apache.m new file mode 100644 index 00000000..48f201ce --- /dev/null +++ b/Recycler/ApacheWO/WOResponse+Apache.m @@ -0,0 +1,146 @@ +// $Id: WOResponse+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#include "WOResponse+Apache.h" +#include +#include +#include +#include "common.h" + +@implementation WOResponse(Apache) + +- (BOOL)applyHeadersOnApacheRequest:(ApacheRequest *)_rq { + static NSMutableSet *ignoredHeaders = nil; + ApacheTable *apHeaders; + NSString *ctype; + NSEnumerator *keys; + NSString *key; + + if (_rq == nil) + return NO; + + if (ignoredHeaders == nil) { + ignoredHeaders = [[NSMutableSet alloc] initWithObjects: + @"content-type", + nil]; + } + + if ((ctype = [self headerForKey:@"content-type"])) + [_rq setContentType:ctype]; + + /* apply all headers ... */ + + apHeaders = [_rq headersOut]; + + keys = [[self headerKeys] objectEnumerator]; + while ((key = [keys nextObject])) { + NSString *svalue; + + if ([ignoredHeaders containsObject:key]) + continue; + + svalue = [[self headersForKey:key] componentsJoinedByString:@", "]; + [apHeaders setObject:svalue forKey:key]; + } + return YES; +} + +- (int)sendContentUsingApacheRequest:(ApacheRequest *)_rq { + return [_rq rwriteData:[self content]]; +} + +- (int)sendResponseUsingApacheRequest:(ApacheRequest *)_rq { + NSAutoreleasePool *pool; + int result; + + result = [self status]; + + pool = [[NSAutoreleasePool alloc] init]; + + [_rq setStatus:[self status]]; + + if (![self applyHeadersOnApacheRequest:_rq]) + result = 500; + else { +#if DONT_SEND_CONTENT_IN_SUBREQUESTS + if ([_rq mainRequest]) { + [self logWithFormat:@"is subrequest (no content is send) ..."]; + } + else { +#endif + [_rq sendHttpHeader]; + + if (![_rq isHeadRequest]) + result = [self sendContentUsingApacheRequest:_rq]; +#if DONT_SEND_CONTENT_IN_SUBREQUESTS + } +#endif + } + + RELEASE(pool); + return ApacheHandledRequest; +} + +@end /* WOResponse(Apache) */ + +@implementation WOResponse(ApacheAppend) + +- (void)appendApacheResponseInfo:(ApacheRequest *)_request { + [self appendContentString:@""]; + +#if 0 + [self appendContentString: + @""]; +#endif + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString: + @""]; + + [self appendContentString:@"
Description:
"];
+  [self appendContentHTMLString:[_request description]];
+  [self appendContentString:@"
Status:"]; + [self appendContentHTMLString:[NSString stringWithFormat:@"%i",[_request status]]]; + [self appendContentString:@"
unparsed URI:"]; + [self appendContentHTMLString:[_request unparsedURI]]; + [self appendContentString:@"
URI:"]; + [self appendContentHTMLString:[_request uri]]; + [self appendContentString:@"
filename:"]; + [self appendContentHTMLString:[_request filename]]; + [self appendContentString:@"
filetype:"]; + [self appendContentHTMLString:[_request fileType]]; + [self appendContentString:@"
content-type:"]; + [self appendContentHTMLString:[_request contentType]]; + [self appendContentString:@"
queryargs:"]; + [self appendContentHTMLString:[_request queryArgs]]; + [self appendContentString:@"
pathinfo:"]; + [self appendContentHTMLString:[_request pathInfo]]; + [self appendContentString:@"
Headers:
"];
+  [self appendContentHTMLString:
+          [[[_request headersOut] asDictionary] description]];
+  [self appendContentString:@"
"]; +} + +@end /* WOResponse(ApacheAppend) */ diff --git a/Recycler/ApacheWO/common.h b/Recycler/ApacheWO/common.h new file mode 100644 index 00000000..dc5d269f --- /dev/null +++ b/Recycler/ApacheWO/common.h @@ -0,0 +1,4 @@ +// $Id: common.h,v 1.1 2004/06/08 11:06:00 helge Exp $ + +#import +#include diff --git a/Recycler/ApacheWO/docs/Embed.wox b/Recycler/ApacheWO/docs/Embed.wox new file mode 100644 index 00000000..700ede60 --- /dev/null +++ b/Recycler/ApacheWO/docs/Embed.wox @@ -0,0 +1,6 @@ + + + I'm a reusable component. + diff --git a/Recycler/ApacheWO/docs/Frame.wox b/Recycler/ApacheWO/docs/Frame.wox new file mode 100644 index 00000000..47ab8599 --- /dev/null +++ b/Recycler/ApacheWO/docs/Frame.wox @@ -0,0 +1,27 @@ + + + + Page: <var:string value="context.page.name"/> + + + +
+ + + +
+ + docs | + test | + requests | + Page2 | + Page3 | + WoPage1 + + + "; + ]]> + diff --git a/Recycler/ApacheWO/docs/Page2.wox b/Recycler/ApacheWO/docs/Page2.wox new file mode 100644 index 00000000..9c0f9196 --- /dev/null +++ b/Recycler/ApacheWO/docs/Page2.wox @@ -0,0 +1,19 @@ + + + Seite 2 ... + + Zur Index-Seite: /docs
+ Zu test.wox: test.wox
+
+ Embed: || +
+
+ bigimg.gif +
+ bigimg.gif +
+ + diff --git a/Recycler/ApacheWO/docs/Page3.wox b/Recycler/ApacheWO/docs/Page3.wox new file mode 100644 index 00000000..0b6c6254 --- /dev/null +++ b/Recycler/ApacheWO/docs/Page3.wox @@ -0,0 +1,32 @@ + + + +
+
+
+
+ + + + + + a:
+ b:
+ c:
+
diff --git a/Recycler/ApacheWO/docs/RqInfo.wox b/Recycler/ApacheWO/docs/RqInfo.wox new file mode 100644 index 00000000..425bda35 --- /dev/null +++ b/Recycler/ApacheWO/docs/RqInfo.wox @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Info on
filename + + () + + [] + +
methodstatuscontent-type
headers-in + + + + + + + +

+
+ + + var rq, value; + var value=""; + +
diff --git a/Recycler/ApacheWO/docs/SSIPage.shtml b/Recycler/ApacheWO/docs/SSIPage.shtml new file mode 100644 index 00000000..cc0afc2c --- /dev/null +++ b/Recycler/ApacheWO/docs/SSIPage.shtml @@ -0,0 +1,17 @@ + + + Server Side Include + + + +

Server Side Include

+ + Today is +
+
+ Inluded .wox page: +
+ +
+ + diff --git a/Recycler/ApacheWO/docs/SlowMarket.gif b/Recycler/ApacheWO/docs/SlowMarket.gif new file mode 100644 index 00000000..32e5c48a Binary files /dev/null and b/Recycler/ApacheWO/docs/SlowMarket.gif differ diff --git a/Recycler/ApacheWO/docs/Table.wox b/Recycler/ApacheWO/docs/Table.wox new file mode 100644 index 00000000..c6e2f2ec --- /dev/null +++ b/Recycler/ApacheWO/docs/Table.wox @@ -0,0 +1,42 @@ + + + + + (/) + = + + + + + + + + + + +
+
+ + + + + + + + + + +
Config Bindings
MaxColumns:
Horizontal:
+ +
+
diff --git a/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.html b/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.html new file mode 100644 index 00000000..d722e4cf --- /dev/null +++ b/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.html @@ -0,0 +1,9 @@ + + .wo based page + + a:
+ b:
+ c:
+ + Action Link to Page2: Page2 +
diff --git a/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.js b/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.js new file mode 100644 index 00000000..074205e6 --- /dev/null +++ b/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.js @@ -0,0 +1,19 @@ + +print("setup WoPage1 ..."); + +var a = 3; +var b = 5; +var c = 0; +var txt = "Hello World !" + +function addAB() { + c = a + b; + return c; +} + +function gotoPage2() { + print("goto page 2 ..."); + var page = pageWithName("Page2"); + print(" page: " + page); + return page; +} diff --git a/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.wod b/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.wod new file mode 100644 index 00000000..6c761f87 --- /dev/null +++ b/Recycler/ApacheWO/docs/WoPage1.wo/WoPage1.wod @@ -0,0 +1,18 @@ +Frame: Frame { + title = name; +} + +AddAB: WOString { + value = addAB; +} + +a: WOString { + value = a; +} +b: WOString { + value = b; +} + +Page2: WOHyperlink { + action = gotoPage2; +} diff --git a/Recycler/ApacheWO/docs/bigimg.gif b/Recycler/ApacheWO/docs/bigimg.gif new file mode 100644 index 00000000..425efe13 Binary files /dev/null and b/Recycler/ApacheWO/docs/bigimg.gif differ diff --git a/Recycler/ApacheWO/docs/imgs/SlowMarket.wox b/Recycler/ApacheWO/docs/imgs/SlowMarket.wox new file mode 100644 index 00000000..496eaab3 --- /dev/null +++ b/Recycler/ApacheWO/docs/imgs/SlowMarket.wox @@ -0,0 +1,6 @@ + + + bigimg.gif + diff --git a/Recycler/ApacheWO/docs/renameme-.htaccess b/Recycler/ApacheWO/docs/renameme-.htaccess new file mode 100644 index 00000000..ae03b60f --- /dev/null +++ b/Recycler/ApacheWO/docs/renameme-.htaccess @@ -0,0 +1,25 @@ +# $Id: .htaccess,v 1.1 2004/06/14 14:59:38 helge Exp $ + +Options FollowSymLinks Indexes Includes + +AddIcon /icons/image2.gif .gif +AddIcon /icons/image1.gif .wox +AddIcon /icons/dir.gif ^^DIRECTORY^^ + +AddDescription "SKYRiX XML template" .wox +AddDescription "SKYRiX WO template" .wo +AddDescription "GIF Image" .gif +AddDescription "Server Side Include" .shtml +AddDescription "SKYRiX Request Handler" .rqh + +FancyIndexing on +IndexOptions FoldersFirst + +#IconHeight 16 +#IconWidth 16 + +SetSxApplication app1 + +AddType text/html .shtml +AddHandler server-parsed .shtml +AddType skyrix/request-handler .rqh diff --git a/Recycler/ApacheWO/docs/requests.wox b/Recycler/ApacheWO/docs/requests.wox new file mode 100644 index 00000000..95c46ce9 --- /dev/null +++ b/Recycler/ApacheWO/docs/requests.wox @@ -0,0 +1,84 @@ + + +

Check Apache Internal Subrequests ..

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Filename:
Pathinfo:
ApacheRequest:
ApacheConnection:
test.wox:
test.wox (file):
test.wox/add:
WoPage1.wo:
blah.wo/:
SSIPage.shtml:
/docs/:
/docs/manage: + Note: pathInfo doesn't work on directories :-(
+ +
+ + + +
diff --git a/Recycler/ApacheWO/docs/subdir/renameme-.htaccess b/Recycler/ApacheWO/docs/subdir/renameme-.htaccess new file mode 100644 index 00000000..e55df2cb --- /dev/null +++ b/Recycler/ApacheWO/docs/subdir/renameme-.htaccess @@ -0,0 +1,3 @@ +# $Id: .htaccess,v 1.1 2004/06/14 14:59:48 helge Exp $ + +LogText "configured in docs/subdir/.htaccess" diff --git a/Recycler/ApacheWO/docs/subdir/test.wox b/Recycler/ApacheWO/docs/subdir/test.wox new file mode 100644 index 00000000..d2eb60cd --- /dev/null +++ b/Recycler/ApacheWO/docs/subdir/test.wox @@ -0,0 +1,8 @@ + + + + +in subdir ... + + + diff --git a/Recycler/ApacheWO/docs/test.html b/Recycler/ApacheWO/docs/test.html new file mode 100644 index 00000000..44e1d919 --- /dev/null +++ b/Recycler/ApacheWO/docs/test.html @@ -0,0 +1,19 @@ + + + + My HTML Page + + + +

My HTML Page

+ + + +
+
Helge Hess
+ + +Last modified: Mon Jun 17 21:10:16 CEST 2002 + + + diff --git a/Recycler/ApacheWO/docs/test.wox b/Recycler/ApacheWO/docs/test.wox new file mode 100644 index 00000000..3ac794ac --- /dev/null +++ b/Recycler/ApacheWO/docs/test.wox @@ -0,0 +1,46 @@ + + +

Apache served .wox page

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ComponentName:
Filename:
Pathinfo:
Context:
Request:
FormValues Keys:
ApacheRequest:
ApacheConnection:
+ + + +
diff --git a/Recycler/ApacheWO/docs/wa.rqh b/Recycler/ApacheWO/docs/wa.rqh new file mode 100644 index 00000000..3eef00e7 --- /dev/null +++ b/Recycler/ApacheWO/docs/wa.rqh @@ -0,0 +1,3 @@ +{ + class = "WODirectActionRequestHandler"; +} diff --git a/Recycler/ApacheWO/docs/xmlrpc.rqh b/Recycler/ApacheWO/docs/xmlrpc.rqh new file mode 100644 index 00000000..b5d4a93f --- /dev/null +++ b/Recycler/ApacheWO/docs/xmlrpc.rqh @@ -0,0 +1,3 @@ +{ + class = "XmlRpcRequestHandler"; +} diff --git a/Recycler/ApacheWO/httpd.conf b/Recycler/ApacheWO/httpd.conf new file mode 100644 index 00000000..81a4a163 --- /dev/null +++ b/Recycler/ApacheWO/httpd.conf @@ -0,0 +1,77 @@ +# $Id: httpd.conf,v 1.1 2004/06/08 11:06:00 helge Exp $ + +# globals +ServerType standalone +ServerRoot "/HOME/helge/mdev/SkyrixRoot" +PidFile /HOME/helge/mdev/SkyrixRoot/logs/httpd8090.pid +ScoreBoardFile /HOME/helge/mdev/SkyrixRoot/logs/httpd8090.scoreboard +DocumentRoot "/HOME/helge/mdev/SkyrixRoot/Library/WebServer/Documents" +ErrorLog /HOME/helge/mdev/SkyrixRoot/logs/error8090_log +AccessFileName .htaccess +Timeout 300 +KeepAlive On +MaxKeepAliveRequests 100 +KeepAliveTimeout 15 +MinSpareServers 1 +MaxSpareServers 1 +StartServers 1 +MaxClients 150 +MaxRequestsPerChild 0 +ExtendedStatus On +Port 8090 +User helge +Group dev +ServerAdmin helge.hess@skyrix.com +HostnameLookups Off +ServerSignature On + +# load Objective-C bundle loader ... + +LoadModule gsbundle_module \ + Libraries/ix86/linux-gnu/apache/mod_gsbundle.so +#AddModule mod_gsbundle.c + +# load a bundle + +LoadApacheBundle ApacheWO.apache +#LoadSxApplication Test.sxa + +AddType application/x-httpd-wox .wox + + + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + +Alias /docs/ "/HOME/helge/mdev/helge/ApacheWO/docs/" + + + # This may also be "None", "All", or any combination of "Indexes", + # "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews". + Options FollowSymLinks + AllowOverride All + + + + order allow,deny + deny from all + + + + order allow,deny + deny from all + + + + SetSxApplication lapp + SetSxRequestHandler WODirectActionRequestHandler + SetHandler sx-handler + + +# Directory-Index could help ... ? +# +# ForceType application/x-httpd-wox +# SetHandler wox-page +# diff --git a/Recycler/ApacheWO/httpd.sh b/Recycler/ApacheWO/httpd.sh new file mode 100755 index 00000000..2fe49545 --- /dev/null +++ b/Recycler/ApacheWO/httpd.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +rm -f core +httpd -X -f $PWD/httpd.conf + diff --git a/Recycler/mod_objc/ApModuleBaseClass+Callbacks.m b/Recycler/mod_objc/ApModuleBaseClass+Callbacks.m new file mode 100644 index 00000000..a69a7182 --- /dev/null +++ b/Recycler/mod_objc/ApModuleBaseClass+Callbacks.m @@ -0,0 +1,396 @@ +// $Id: ApModuleBaseClass+Callbacks.m,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#include "ApModuleBaseClass.h" +#include +#include "http_config.h" +#import +#import +#import +#include "ApacheServer.h" +#include "ApacheResourcePool.h" +#include "ApacheModule.h" +#include "ApacheRequest.h" + +@implementation ApModuleBaseClass(BasicModuleCallbacks) + ++ (void)_moduleInit:(void *)s pool:(void *)p { + NSAutoreleasePool *pool; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheServer *os; + ApacheResourcePool *op; + + os = [[ApacheServer alloc] initWithHandle:s]; + op = [[ApacheResourcePool alloc] initWithHandle:p]; + [bundleHandler initializeModuleForServer:os inPool:op]; + RELEASE(op); op = nil; + RELEASE(os); os = nil; + } + RELEASE(pool); +} + ++ (void *)_perDirConfCreate:(void *)dirspec pool:(void *)p { + NSAutoreleasePool *pool; + id result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return NULL; + } + + result = nil; + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheResourcePool *op; + + op = [[ApacheResourcePool alloc] initWithHandle:p]; + + result = [bundleHandler createPerDirectoryConfigInPool:op]; + if (result) { + /* let apache release config ... */ + RETAIN(result); + [op releaseObject:result]; + } + + RELEASE(op); op = nil; + } + RELEASE(pool); + return result; +} + ++ (void *)_perDirConfMerge:(void *)baseCconf with:(void *)newCconf + pool:(void *)p +{ + NSAutoreleasePool *pool; + id result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return NULL; + } + + result = nil; + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheResourcePool *op; + + op = [[ApacheResourcePool alloc] initWithHandle:p]; + + result = [bundleHandler mergePerDirectoryBaseConfig:baseCconf + withNewConfig:newCconf + inPool:op]; + if (result) { + /* let apache release config ... */ + RETAIN(result); + [op releaseObject:result]; + } + + RELEASE(op); op = nil; + } + RELEASE(pool); + return result; +} + ++ (void *)_perServerConfCreate:(void *)s pool:(void *)p { + NSAutoreleasePool *pool; + id result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return NULL; + } + + result = nil; + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheServer *os; + ApacheResourcePool *op; + + os = [[ApacheServer alloc] initWithHandle:s]; + op = [[ApacheResourcePool alloc] initWithHandle:p]; + + result = [bundleHandler createPerServerConfig:os inPool:op]; + if (result) { + /* let apache release config ... */ + RETAIN(result); + [op releaseObject:result]; + } + + RELEASE(op); op = nil; + RELEASE(os); os = nil; + } + RELEASE(pool); + return result; +} ++ (void *)_perServerConfMerge:(void *)baseConf with:(void *)newConf + pool:(void *)p +{ + NSAutoreleasePool *pool; + id result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return NULL; + } + + result = nil; + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheResourcePool *op; + + op = [[ApacheResourcePool alloc] initWithHandle:p]; + + result = [bundleHandler mergePerServerBaseConfig:baseConf + withNewConfig:newConf + inPool:op]; + if (result) { + /* let apache release config ... */ + RETAIN(result); + [op releaseObject:result]; + } + + RELEASE(op); op = nil; + } + RELEASE(pool); + return result; +} + ++ (int)_translateHandler:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler handleTranslationForRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_apCheckUserId:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler checkUserIdFromRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_authChecker:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler checkAuthForRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_accessChecker:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler checkAccessForRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_typeChecker:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler checkTypeForRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_fixerUpper:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler fixupRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_logger:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler logRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} ++ (int)_headerParser:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler parseHeadersOfRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} + ++ (void)_childInit:(void *)_server pool:(void *)_pool { + NSAutoreleasePool *pool; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheResourcePool *op; + ApacheServer *sr; + + op = [[ApacheResourcePool alloc] initWithHandle:_pool]; + sr = [[ApacheServer alloc] initWithHandle:_server]; + [bundleHandler initializeChildProcessWithServer:sr inPool:op]; + RELEASE(sr); + RELEASE(op); + } + RELEASE(pool); +} ++ (void)_childExit:(void *)_server pool:(void *)_pool { + NSAutoreleasePool *pool; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheResourcePool *op; + ApacheServer *sr; + + op = [[ApacheResourcePool alloc] initWithHandle:_pool]; + sr = [[ApacheServer alloc] initWithHandle:_server]; + [bundleHandler exitChildProcessWithServer:sr inPool:op]; + RELEASE(sr); + RELEASE(op); + } + RELEASE(pool); +} + ++ (int)_postReadRequest:(void *)_request { + NSAutoreleasePool *pool; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return DECLINED; + } + + pool = [[NSAutoreleasePool alloc] init]; + { + ApacheRequest *or; + or = [[ApacheRequest alloc] initWithHandle:_request]; + result = [bundleHandler postProcessRequest:or]; + RELEASE(or); + } + RELEASE(pool); + return result; +} + +@end /* ApModuleBaseClass(BasicModuleCallbacks) */ diff --git a/Recycler/mod_objc/ApModuleBaseClass+Cmds.m b/Recycler/mod_objc/ApModuleBaseClass+Cmds.m new file mode 100644 index 00000000..9a6684ee --- /dev/null +++ b/Recycler/mod_objc/ApModuleBaseClass+Cmds.m @@ -0,0 +1,864 @@ +// $Id: ApModuleBaseClass+Cmds.m,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#include "ApModuleBaseClass.h" +#include +#include "http_config.h" +#import +#import +#import +#include "ApacheServer.h" +#include "ApacheResourcePool.h" +#include "ApacheModule.h" +#include "ApacheCmdParms.h" + +@implementation ApModuleBaseClass(ConfigCommands) + +static const char *configStubRaw(cmd_parms *p, void *d, char *a0); +static const char *configStubFlag(cmd_parms *p, void *d, int flag); +static const char *configStubTake0(cmd_parms *p, void *d); +static const char *configStubTake1(cmd_parms *p, void *d, char *a0); +static const char *configStubTake2(cmd_parms *p, void *d, char *a0, char *a1); +static const char *configStubTake12(cmd_parms *p, void *d, char *a0, char *a1); +static const char * + configStubTake3(cmd_parms *p, void *d, char *a0, char *a1, char *a3); +static const char * + configStubTake123(cmd_parms *p, void *d, char *a0, char *a1, char *a3); + +static const char * + configStubIterate(cmd_parms *p, void *d, char *a0); +static const char * + configStubIterate2(cmd_parms *p, void *d, char *a0, char *a1); + +static const char *serverConfigStubRaw(cmd_parms *p, void *d, char *a0); +static const char *serverConfigStubFlag(cmd_parms *p, void *d, int flag); +static const char *serverConfigStubTake0(cmd_parms *p, void *d); +static const char *serverConfigStubTake1(cmd_parms *p, void *d, char *a0); +static const char * + serverConfigStubTake2(cmd_parms *p, void *d, char *a0, char *a1); +static const char * + serverConfigStubTake12(cmd_parms *p, void *d, char *a0, char *a1); +static const char * + serverConfigStubTake3(cmd_parms *p, void *d, char *a0, char *a1, char *a3); +static const char * + serverConfigStubTake123(cmd_parms *p, void *d, char *a0, char *a1, char *a3); + +static const char * + serverConfigStubIterate(cmd_parms *p, void *d, char *a0); +static const char * + serverConfigStubIterate2(cmd_parms *p, void *d, char *a0, char *a1); + +typedef struct _ObjCmdDispatchInfo { + Class moduleClass; + SEL sel; + const char *methodName; + const char *command; + enum cmd_how argsHow; + int location; + BOOL isIterate; + BOOL isFlag; + BOOL isRaw; +} ApObjCCmdDispatchInfo; + ++ (BOOL)logConfigCommandRegistration { + return NO; +} + ++ (command_rec *)apacheCommandTable { + /* + How to map selectors to commands ? + + All command selectors start with 'configure', eg: + + paras TAKE2, location ACCESS_CONF + - configureDirectory_ScriptAlias:(NSString *)_fake:(NSString *)_real + directoryConfig:(id)_cfg + parameters:(ApacheCmdParms *)_params; + + paras TAKE2, location RSRC_CONF + - configureServer_ScriptAlias:(NSString *)_fake:(NSString *)_real + parameters:(ApacheCmdParms *)_params; + + paras TAKE1, location OR_FILEINFO + - configureFileInfo_PassEnv:(NSString *)_arg + directoryConfig:(id)_cfg + parameters:(ApacheCmdParms *)_params; + + paras FLAG, location OR_FILEINFO + - configureFileInfo_PassEnvFlag:(BOOL)_flag + directoryConfig:(id)_cfg + parameters:(ApacheCmdParms *)_params; + + paras ITERATE, location OR_INDEXES + - configureIndexes_DirectoryIndexIterate:(NSString *)_dir + directoryConfig:(id)_cfg + parameters:(ApacheCmdParms *)_params; + + Allowed Prefixes: + configureDirectory_ + configureServer_ + configureFileInfo_ + configureIndexes_ + + Parameters: + RAW_ARGS, // cmd_func parses command line itself + TAKE1, // one argument only + TAKE2, // two arguments only + ITERATE, // one argument, occuring multiple times + // (e.g., IndexIgnore) + ITERATE2, // two arguments, 2nd occurs multiple times + // (e.g., AddIcon) + FLAG, // One of 'On' or 'Off' + NO_ARGS, // No args at all, e.g. + TAKE12, // one or two arguments + TAKE3, // three arguments only + TAKE23, // two or three arguments + TAKE123, // one, two or three arguments + TAKE13 // one or three arguments + + Request Overrides + * The allowed locations for a configuration directive are the union of + * those indicated by each set bit in the req_override mask. + * + * (req_override & RSRC_CONF) => *.conf outside or + * (req_override & ACCESS_CONF) => *.conf inside or + * (req_override & OR_AUTHCFG) => *.conf inside or + * and .htaccess when AllowOverride + * AuthConfig + * (req_override & OR_LIMIT) => *.conf inside or + * and .htaccess when AllowOverride Limit + * (req_override & OR_OPTIONS) => *.conf anywhere + * and .htaccess when AllowOverride Options + * (req_override & OR_FILEINFO) => *.conf anywhere + * and .htaccess when AllowOverride FileInfo + * (req_override & OR_INDEXES) => *.conf anywhere + * and .htaccess when AllowOverride Indexes + + typedef struct command_struct { + const char *name; // Name of this command + const char *(*func) (); // Function invoked + void *cmd_data; // Extra data, for functions which + // implement multiple commands... + int req_override; // What overrides need to be allowed to + // enable this command. + enum cmd_how args_how; // What the command expects as arguments + + const char *errmsg; // 'usage' message, in case of syntax errors + } command_rec; + */ + ApacheModule *bundleHandler = [self bundleHandler]; + command_rec *cmdtable; + + unsigned count, capacity; + Class c; + + if (bundleHandler == nil) + return NULL; + + count = 0; + capacity = 16; + cmdtable = calloc(capacity + 1, sizeof(command_rec)); + +#if GNU_RUNTIME + /* for the class and each superclass ... */ + for (c = [bundleHandler class]; c != Nil; c = c->super_class) { + struct objc_method_list *cm; + + /* for each method list of the class */ + for (cm = c->methods; cm != NULL; cm = cm->method_next) { + register unsigned i; + + /* for each method in the list */ + for (i = 0; i < cm->method_count; i++) { + const char *methodName; + const char *tmp; + char *tmp2, *tmp3; + unsigned len, argumentCount; + char *configName; + int reqOverride = 0; + enum cmd_how argsHow = 0; + BOOL hasParametersArg; + BOOL hasDirConfigArg; + BOOL isIterate; + BOOL isFlag; + BOOL isRaw; + + if ((methodName = sel_get_name(cm->method_list[i].method_name))==NULL) + continue; + if (methodName[0] != 'c') + /* quick check for 'configure' prefix */ + continue; + + if (strstr(methodName, "configure") != methodName) + /* long check for 'configure' prefix */ + continue; + + tmp = methodName + 9; + + /* search for start of config name, eg _PassEnv */ + + if ((tmp2 = index(tmp, '_')) == NULL) + continue; + tmp2++; // skip underscore + + /* search for end of config name, copy config name */ + + if ((tmp3 = index(tmp2, ':')) == NULL) + continue; + if ((len = (tmp3 - tmp2)) < 3) + /* config name to short ... */ + continue; + + configName = malloc(len + 2); + memcpy(&(configName[0]), tmp2, len); + configName[len] = '\0'; + + /* count args */ + + for (argumentCount = 0; *tmp3 == ':'; tmp3++) + argumentCount++; + tmp3 = NULL; + + if (argumentCount == 0 || argumentCount > 3) { + printf("ERROR(%s): flag and raw configuration selectors " + "only take exactly one argument (sel=%s, command=%s) !!!\n", + __PRETTY_FUNCTION__, methodName, configName); + continue; + } + + /* check suffix (Iterate, Flag) */ + + isIterate = NO; + isFlag = NO; + isRaw = NO; + if ((tmp3 = rindex(configName, 'I'))) { + if (strcmp(tmp3, "Iterate") == 0) { + *tmp3 = '\0'; + isIterate = YES; + } + } + if ((tmp3 = rindex(configName, 'F'))) { + if (strcmp(tmp3, "Flag") == 0) { + *tmp3 = '\0'; + isFlag = YES; + } + } + if ((tmp3 = rindex(configName, 'R'))) { + if (strcmp(tmp3, "Raw") == 0) { + *tmp3 = '\0'; + isRaw = YES; + } + } + + /* derive argument style info */ + + if ((isFlag || isRaw) && (argumentCount != 1)) { + if (argumentCount != 1) { + printf("ERROR(%s): flag and raw configuration selectors " + "only take exactly one argument (sel=%s, command=%s) !!!\n", + __PRETTY_FUNCTION__, methodName, configName); + continue; + } + } + + if (isFlag) { + argsHow = FLAG; + } + else if (isIterate) { + if (argumentCount == 1) + argsHow = ITERATE; + else if (argumentCount == 2) + argsHow = ITERATE2; + else { + printf("ERROR(%s): iterate configuration selectors " + "only take one or two arguments (sel=%s, command=%s) !!!\n", + __PRETTY_FUNCTION__, methodName, configName); + continue; + } + } + else if (isRaw) { + argsHow = RAW_ARGS; + } + else { + switch (argumentCount) { + case 0: + argsHow = NO_ARGS; + break; + case 1: + argsHow = TAKE1; + break; + case 2: + argsHow = TAKE2; + break; + case 3: + argsHow = TAKE3; + break; + default: + printf("ERROR(%s): configuration selectors " + "only take 1-3 arguments (sel=%s, command=%s) !!!\n", + __PRETTY_FUNCTION__, methodName, configName); + continue; + } + } + + /* search for standard parameters */ + + hasParametersArg = strstr(tmp2, "parameters:") != NULL ? YES : NO; + hasDirConfigArg = strstr(tmp2, "directoryConfig:") != NULL ? YES : NO; + + if ([self logConfigCommandRegistration]) { + printf("Found config selector '%s', command '%s' (%i args) ...\n", + methodName, configName, argumentCount); + } + + /* check allowed location */ + + switch (tmp[0]) { + case 'D': + if (strstr(tmp, "Directory") == tmp) { + reqOverride = ACCESS_CONF; + break; + } + case 'S': + if (strstr(tmp, "Server") == tmp) { + reqOverride = RSRC_CONF; + break; + } + case 'I': + if (strstr(tmp, "Indexes") == tmp) { + reqOverride = OR_INDEXES; + break; + } + case 'F': + if (strstr(tmp, "FileInfo") == tmp) { + reqOverride = OR_FILEINFO; + break; + } + case 'O': + if (strstr(tmp, "Options") == tmp) { + reqOverride = OR_OPTIONS; + break; + } + case 'L': + if (strstr(tmp, "Limit") == tmp) { + reqOverride = OR_OPTIONS; + break; + } + case 'A': + if (strstr(tmp, "AuthConfig") == tmp) { + reqOverride = OR_AUTHCFG; + break; + } + default: + printf("%s: invalid directory location in selector '%s' !\n", + __PRETTY_FUNCTION__, methodName); + continue; + } + + /* should check for duplicate entries */ + { + int i; + + for (i = 0; i < count; i++) { + if (strcmp(cmdtable[i].name, configName) == 0) { + /* this should check for alternate argument counts */ + printf("WARNING(%s): found duplicate entry '%s' ...\n", + __PRETTY_FUNCTION__, configName); + i = -1; + break; + } + } + if (i == -1) continue; + } + + /* check command table capacity */ + + if (count >= capacity) { + /* resize command table ... */ + command_rec *old = cmdtable; + unsigned oldCapacity = capacity; + + capacity *= 2; + cmdtable = calloc(capacity + 1,sizeof(command_rec)); + memcpy(cmdtable, old, oldCapacity * sizeof(command_rec)); + if (old) free(old); + } + + /* fill command table entry */ + + cmdtable[count].name = configName /* malloced */; + cmdtable[count].args_how = argsHow; + cmdtable[count].req_override = reqOverride; + + { + NSString *err; + + err = [bundleHandler usageForConfigSelector: + cm->method_list[i].method_name]; + + cmdtable[count].errmsg = [err length] > 0 + ? strdup([err cString]) + : NULL; + } + + { + ApObjCCmdDispatchInfo *info; + + info = calloc(1, sizeof(ApObjCCmdDispatchInfo)); + info->moduleClass = self; + info->sel = cm->method_list[i].method_name; + info->methodName = methodName; + info->command = configName; + info->argsHow = cmdtable[count].args_how; + info->location = cmdtable[count].req_override; + info->isRaw = isRaw; + info->isIterate = isIterate; + info->isFlag = isFlag; + + cmdtable[count].cmd_data = info; + } + + { + void *func; + + func = NULL; + if (reqOverride != RSRC_CONF) { + switch (cmdtable[count].args_how) { + case NO_ARGS: func = configStubTake0; break; + case RAW_ARGS: func = configStubRaw; break; + case TAKE1: func = configStubTake1; break; + case ITERATE: func = configStubIterate; break; + case TAKE2: func = configStubTake2; break; + case TAKE12: func = configStubTake12; break; + case ITERATE2: func = configStubIterate2; break; + case TAKE3: func = configStubTake3; break; + case TAKE23: break; + case TAKE123: func = configStubTake123; break; + case TAKE13: break; + case FLAG: func = configStubFlag; break; + + default: + printf("ERROR(%s): unknown argument style %i !!\n", + __PRETTY_FUNCTION__, cmdtable[count].args_how); + break; + } + } + else { + switch (cmdtable[count].args_how) { + case NO_ARGS: func = serverConfigStubTake0; break; + case RAW_ARGS: func = serverConfigStubRaw; break; + case TAKE1: func = serverConfigStubTake1; break; + case ITERATE: func = serverConfigStubIterate; break; + case TAKE2: func = serverConfigStubTake2; break; + case TAKE12: func = serverConfigStubTake12; break; + case ITERATE2: func = serverConfigStubIterate2; break; + case TAKE3: func = serverConfigStubTake3; break; + case TAKE23: break; + case TAKE123: func = serverConfigStubTake123; break; + case TAKE13: break; + case FLAG: func = serverConfigStubFlag; break; + + default: + printf("ERROR(%s): unknown argument style %i !!\n", + __PRETTY_FUNCTION__, cmdtable[count].args_how); + break; + } + } + cmdtable[count].func = func; + } + if (cmdtable[count].func) + count++; + else { + printf("ERROR(%s): internal error during cmd table setup ...\n", + __PRETTY_FUNCTION__); + } + } + } + } +#else +# warning not ported to this runtime yet ... +#endif + + if (count == 0) { + /* found no commands ... */ + if (cmdtable) { + free(cmdtable); + cmdtable = NULL; + } + } +#if 0 + printf("found %i commands ...\n", count); +#endif + return cmdtable; +} + +#define OBJC_CONFIG_BEGIN \ + NSAutoreleasePool *pool;\ + ApObjCCmdDispatchInfo *info;\ + ApacheCmdParms *paras;\ + ApacheModule *bundleHandler;\ + const char *ares;\ + if ((info = p->info) == NULL)\ + return ap_pstrdup(p->pool, "missing Objective-C dispatch info !");\ + pool = [[NSAutoreleasePool alloc] init];\ + paras = [[ApacheCmdParms alloc] initWithHandle:p];\ + bundleHandler = [[info->moduleClass bundleHandler] retain];\ + { id result; result = nil; + +#define OBJC_CONFIG_END \ + if (result == nil) ares = NULL;\ + else ares = ap_pstrdup(p->pool, [[result description] cString]);\ + }\ + RELEASE(bundleHandler);\ + RELEASE(paras);\ + RELEASE(pool); \ + return ares; + +static const char *configStubRaw(cmd_parms *p, void *d, char *a0) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, id, ApacheCmdParms *); + NSString *s0; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char *configStubFlag(cmd_parms *p, void *d, int flag) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, BOOL, id, ApacheCmdParms *); + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, flag?YES:NO, d, paras); + else + result = @"did not find method for config call .."; + } + OBJC_CONFIG_END; +} +static const char *configStubTake1(cmd_parms *p, void *d, char *a0) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, id, ApacheCmdParms *); + NSString *s0; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +static const char *configStubIterate(cmd_parms *p, void *d, char *a0) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, id, ApacheCmdParms *); + NSString *s0; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char + *configStubIterate2(cmd_parms *p, void *d, char *a0, char *a1) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, id, ApacheCmdParms *); + NSString *s0, *s1; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +static const char *configStubTake0(cmd_parms *p, void *d) { + return NULL; +} + +static const char *configStubTake2(cmd_parms *p, void *d, char *a0, char *a1) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, id, ApacheCmdParms *); + NSString *s0, *s1; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +static const char *configStubTake12(cmd_parms *p, void *d, char *a0, char *a1){ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, id, ApacheCmdParms *); + NSString *s0, *s1; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char * + configStubTake3(cmd_parms *p, void *d, char *a0, char *a1, char *a2) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, NSString *,id, ApacheCmdParms *); + NSString *s0, *s1, *s2; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + s2 = a2 ? [[NSString alloc] initWithCString:a2] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, s2, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s2); + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char * + configStubTake123(cmd_parms *p, void *d, char *a0, char *a1, char *a2) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, NSString *,id, ApacheCmdParms *); + NSString *s0, *s1, *s2; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + s2 = a2 ? [[NSString alloc] initWithCString:a2] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, s2, d, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s2); + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +/* server stubs */ + +static const char *serverConfigStubRaw(cmd_parms *p, void *d, char *a0) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, ApacheCmdParms *); + NSString *s0; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char *serverConfigStubFlag(cmd_parms *p, void *d, int flag) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, BOOL, ApacheCmdParms *); + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, flag?YES:NO, paras); + else + result = @"did not find method for config call .."; + } + OBJC_CONFIG_END; +} +static const char *serverConfigStubTake1(cmd_parms *p, void *d, char *a0) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, ApacheCmdParms *); + NSString *s0; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +static const char *serverConfigStubIterate(cmd_parms *p, void *d, char *a0) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, ApacheCmdParms *); + NSString *s0; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char + *serverConfigStubIterate2(cmd_parms *p, void *d, char *a0, char *a1) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, ApacheCmdParms *); + NSString *s0, *s1; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +static const char *serverConfigStubTake0(cmd_parms *p, void *d) { + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, ApacheCmdParms *); + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, paras); + else + result = @"did not find method for config call .."; + } + OBJC_CONFIG_END; +} + +static const char * +serverConfigStubTake2(cmd_parms *p, void *d, char *a0, char *a1) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, ApacheCmdParms *); + NSString *s0, *s1; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +static const char * +serverConfigStubTake12(cmd_parms *p, void *d, char *a0, char *a1) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, ApacheCmdParms *); + NSString *s0, *s1; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char * + serverConfigStubTake3(cmd_parms *p, void *d, char *a0, char *a1, char *a2) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, NSString *, ApacheCmdParms *); + NSString *s0, *s1, *s2; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + s2 = a2 ? [[NSString alloc] initWithCString:a2] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, s2, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s2); + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} +static const char * + serverConfigStubTake123(cmd_parms *p, void *d, char *a0, char *a1, char *a2) +{ + OBJC_CONFIG_BEGIN { + id (*m)(id, SEL, NSString *, NSString *, NSString *, ApacheCmdParms *); + NSString *s0, *s1, *s2; + + s0 = a0 ? [[NSString alloc] initWithCString:a0] : nil; + s1 = a1 ? [[NSString alloc] initWithCString:a1] : nil; + s2 = a2 ? [[NSString alloc] initWithCString:a2] : nil; + + if ((m = (void *)[bundleHandler methodForSelector:info->sel])) + result = m(bundleHandler, info->sel, s0, s1, s2, paras); + else + result = @"did not find method for config call .."; + + RELEASE(s2); + RELEASE(s1); + RELEASE(s0); + } + OBJC_CONFIG_END; +} + +@end /* ApModuleBaseClass(ConfigCommands) */ diff --git a/Recycler/mod_objc/ApModuleBaseClass+Handler.m b/Recycler/mod_objc/ApModuleBaseClass+Handler.m new file mode 100644 index 00000000..9a59f53f --- /dev/null +++ b/Recycler/mod_objc/ApModuleBaseClass+Handler.m @@ -0,0 +1,359 @@ +// $Id: ApModuleBaseClass+Handler.m,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#include "ApModuleBaseClass.h" +#include +#include "http_config.h" +#import +#import +#import +#include "ApacheServer.h" +#include "ApacheResourcePool.h" +#include "ApacheModule.h" +#include "ApacheRequest.h" + +@implementation ApModuleBaseClass(HandlerCallback) + ++ (BOOL)logHandlerRegistration { + return NO; +} + ++ (handler_rec *)apacheHandlerTable { + /* + KNOWN problem: this method produces memory leaks !! + + How to map selectors to handlers ? + + There are two-kinds, content-type handlers and named handlers: + + text/plain -> + - (int)handleTextPlainRequest:(ApacheRequest *)_rq; + ngobjweb-adaptor -> + - (int)performNgobjwebAdaptorRequest:(ApacheRequest *)_rq; + + // This structure records the existence of handlers in a module... + + typedef struct { + const char *content_type; // MUST be all lower case + int (*handler) (request_rec *); + } handler_rec; + */ + ApacheModule *bundleHandler = [self bundleHandler]; + handler_rec *handlerTable = NULL; + unsigned count, capacity; + Class c; + + if (bundleHandler == nil) + return NULL; + + count = 0; + capacity = 16; + handlerTable = calloc(capacity + 1, sizeof(handler_rec)); + +#if GNU_RUNTIME + /* for the class and each superclass ... */ + for (c = [bundleHandler class]; c != Nil; c = c->super_class) { + struct objc_method_list *cm; + + /* for each method list of the class */ + for (cm = c->methods; cm != NULL; cm = cm->method_next) { + register unsigned i; + + /* for each method in the list */ + for (i = 0; i < cm->method_count; i++) { + const char *methodName; + + if ((methodName = sel_get_name(cm->method_list[i].method_name))) { + if (strstr(methodName, "handle") == methodName) { + /* could be a MIME-type handler ... */ + const unsigned char *rq, *spec; + unsigned j, len, n, bufLen; + unsigned char *buf; + + if ((rq = strstr(methodName, "Request:")) == NULL) + continue; + + spec = methodName + 6; /* skip 'handle' */ + if ((len = (rq - spec)) == 0) { + /* type spec too long or too short ... */ + continue; + } + + bufLen = len * 2 + 2; + buf = malloc(bufLen); + + buf[0] = tolower(spec[0]); + for (j = 1, n = 1; j < len; j++) { + if (isupper(spec[j])) { + buf[n] = '/'; + n++; + buf[n] = tolower(spec[j]); + n++; + } + else { + buf[n] = spec[j]; + n++; + } + } + buf[n] = '\0'; + + if (count >= capacity) { + /* resize handler table ... */ + handler_rec *old = handlerTable; + unsigned oldCapacity = capacity; + + capacity *= 2; + handlerTable = calloc(capacity + 1,sizeof(handler_rec)); + memcpy(handlerTable, old, oldCapacity * sizeof(handler_rec)); + if (old) free(old); + } + + /* memory dup'ed is currently never freed ! */ + + handlerTable[count].content_type = buf; + handlerTable[count].handler = [self handleRequestStubFunction]; + count++; + + if ([self logHandlerRegistration]) { + printf("%s: found method '%s' for MIME handler '%s' ...\n", + __PRETTY_FUNCTION__, methodName, buf); + } + } + else if (strstr(methodName, "perform") == methodName) { + /* could be a named handler ... */ + const unsigned char *rq, *spec; + unsigned j, len, n, bufLen; + unsigned char *buf; + + if ((rq = strstr(methodName, "Request:")) == NULL) + continue; + spec = methodName + 7; /* skip 'perform' */ + if ((len = (rq - spec)) == 0) { + /* type spec too long or too short ... */ + continue; + } + + bufLen = len * 2 + 2; + buf = malloc(bufLen); + + buf[0] = tolower(spec[0]); + for (j = 1, n = 1; j < len; j++) { + if (isupper(spec[j])) { + buf[n] = '-'; + n++; + buf[n] = tolower(spec[j]); + n++; + } + else { + buf[n] = spec[j]; + n++; + } + } + buf[n] = '\0'; + + if (count >= capacity) { + /* resize handler table ... */ + handler_rec *old = handlerTable; + unsigned oldCapacity = capacity; + + capacity *= 2; + handlerTable = calloc(capacity + 1,sizeof(handler_rec)); + memcpy(handlerTable, old, oldCapacity * sizeof(handler_rec)); + if (old) free(old); + } + + /* memory dup'ed is currently never freed ! */ + + handlerTable[count].content_type = buf; + handlerTable[count].handler = [self handleRequestStubFunction]; + count++; + + if ([self logHandlerRegistration]) { + printf("%s: found method '%s' for named handler '%s' ...\n", + __PRETTY_FUNCTION__, methodName, buf); + } + } + } + } + } + } + +#else +# warning not ported to this runtime yet ... +#endif + + if (count == 0) { + /* found no handlers ... */ + if (handlerTable) { + free(handlerTable); + handlerTable = NULL; + } + } +#if 0 + printf("found %i handlers ...\n", count); +#endif + return handlerTable; +} + +/* the request dispatcher */ + ++ (int)_handleRequest:(void *)_request { + request_rec *req = _request; + int result; + ApacheModule *bundleHandler = [self bundleHandler]; + + if (bundleHandler == nil) { + printf("%s: missing bundle handler !!!\n", __PRETTY_FUNCTION__); + return 500; + } + + result = DECLINED; + + if (req->handler) { + /* dispatch based on handler set ... */ + unsigned len; + + if ((len = strlen(req->handler)) > 0) { + unsigned char *buf; + unsigned i, j; + int (*h)(id,SEL,id); + SEL sel; + BOOL nextUpper; + + buf = calloc(len + 64, sizeof(char)); + strcpy(buf, "perform"); + for (i = 0, j = strlen(buf), nextUpper = YES; i < len; i++) { + if (req->handler[i] == '-') { + /* skip dash and add next char in uppercase */ + nextUpper = YES; + } + else { + buf[j] = (nextUpper) + ? toupper(req->handler[i]) + : req->handler[i]; + j++; + nextUpper = NO; + } + } + buf[j] = '\0'; + strcat(buf, "Request:"); + sel = sel_get_any_uid(buf); + free(buf); + buf = NULL; + +#if 0 + printf("CALL: %s\n", sel_get_name(sel)); + fflush(stdout); +#endif + + if (sel == NULL) { + fprintf(stderr, + "%s: did not find selector for handler '%s' !\n", + __PRETTY_FUNCTION__, req->handler); + result = 500; + } + else if ((h = (void *)[bundleHandler methodForSelector:sel])) { + NSAutoreleasePool *pool; + ApacheRequest *or; + + pool = [[NSAutoreleasePool alloc] init]; + or = [[ApacheRequest alloc] initWithHandle:_request]; + + result = h(bundleHandler, sel, or); + + if (result == ApacheDeclineRequest) + result = DECLINED; + else if (result == ApacheHandledRequest) + result = OK; + + RELEASE(or); + RELEASE(pool); + } + else { + fprintf(stderr, + "%s: did not find handler method '%s' for name '%s' !\n", + __PRETTY_FUNCTION__, sel_get_name(sel), req->handler); + result = 500; + } + } + } + else if (req->content_type) { + /* dispatch based on MIME-type ... */ + unsigned len; + + if ((len = strlen(req->content_type)) > 0) { + unsigned char *buf; + unsigned i, j; + int (*h)(id,SEL,id); + SEL sel; + BOOL nextUpper; + + buf = calloc(len + 64, sizeof(char)); + strcpy(buf, "handle"); + for (i = 0, j = strlen(buf), nextUpper = YES; i < len; i++) { + if (req->content_type[i] == '/') { + /* skip slash and add next char in uppercase */ + nextUpper = YES; + } + else { + buf[j] = (nextUpper) + ? toupper(req->content_type[i]) + : req->content_type[i]; + j++; + nextUpper = NO; + } + } + buf[j] = '\0'; + strcat(buf, "Request:"); + sel = sel_get_any_uid(buf); + free(buf); + buf = NULL; + +#if 0 + printf("CALL: %s\n", sel_get_name(sel)); + fflush(stdout); +#endif + + if (sel == NULL) { + fprintf(stderr, + "%s: did not find selector for mime type '%s' !\n", + __PRETTY_FUNCTION__, req->content_type); + result = 500; + } + else if ((h = (void *)[bundleHandler methodForSelector:sel])) { + NSAutoreleasePool *pool; + ApacheRequest *or; + + pool = [[NSAutoreleasePool alloc] init]; + or = [[ApacheRequest alloc] initWithHandle:_request]; + + result = h(bundleHandler, sel, or); + + if (result == ApacheDeclineRequest) + result = DECLINED; + else if (result == ApacheHandledRequest) + result = OK; + + RELEASE(or); + RELEASE(pool); + } + else { + fprintf(stderr, + "%s: did not find handler method '%s' for mime type '%s' !\n", + __PRETTY_FUNCTION__, sel ? sel_get_name(sel) : "", + req->content_type); + result = 500; + } + } + } + else { + /* nothing to dispatch on ... */ + fprintf(stderr, + "%s: found nothing to dispatch on " + "(neither handler type nor name) !\n", + __PRETTY_FUNCTION__); + result = DECLINED; + } + return result; +} + +@end /* ApModuleBaseClass(HandlerCallback) */ diff --git a/Recycler/mod_objc/ApModuleBaseClass.h b/Recycler/mod_objc/ApModuleBaseClass.h new file mode 100644 index 00000000..f5c3ba1e --- /dev/null +++ b/Recycler/mod_objc/ApModuleBaseClass.h @@ -0,0 +1,66 @@ +// $Id: ApModuleBaseClass.h,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#ifndef __ApModuleBaseClass_H__ +#define __ApModuleBaseClass_H__ + +#import + +@class ApacheModule; + +@interface ApModuleBaseClass : NSObject + ++ (void)setBundleHandler:(ApacheModule *)_handler; ++ (ApacheModule *)bundleHandler; + +/* return an initialized Apache module structure ... */ ++ (void *)apacheModule; + +@end + +@interface ApModuleBaseClass(SubclassOverrides) + +/* return an Apache module structure with all callback wrappers set ... */ ++ (void *)apacheTemplateModule; + +/* return the uninitialized Apache module structure */ ++ (void *)apacheModuleStructure; + +/* the stub to dispatch handlers (placed in the handler_rec structure) */ ++ (void *)handleRequestStubFunction; + +@end + +@interface ApModuleBaseClass(BasicModuleCallbacks) + ++ (void)_moduleInit:(void *)s pool:(void *)p; + ++ (void *)_perDirConfCreate:(void *)dirspec pool:(void *)p; ++ (void *)_perDirConfMerge:(void *)baseCconf with:(void *)newCconf + pool:(void *)p; ++ (void *)_perServerConfCreate:(void *)s pool:(void *)p; ++ (void *)_perServerConfMerge:(void *)baseConf with:(void *)newConf + pool:(void *)p; + ++ (int)_translateHandler:(void *)_request; ++ (int)_apCheckUserId:(void *)_request; ++ (int)_authChecker:(void *)_request; ++ (int)_accessChecker:(void *)_request; ++ (int)_typeChecker:(void *)_request; ++ (int)_fixerUpper:(void *)_request; ++ (int)_logger:(void *)_request; ++ (int)_headerParser:(void *)_request; + ++ (void)_childInit:(void *)_server pool:(void *)_pool; ++ (void)_childExit:(void *)_server pool:(void *)_pool; + ++ (int)_postReadRequest:(void *)_request; + +@end + +@interface ApModuleBaseClass(HandlerCallback) + ++ (int)_handleRequest:(void *)_request; + +@end + +#endif /* ApModuleBaseClass */ diff --git a/Recycler/mod_objc/ApModuleBaseClass.m b/Recycler/mod_objc/ApModuleBaseClass.m new file mode 100644 index 00000000..3919907a --- /dev/null +++ b/Recycler/mod_objc/ApModuleBaseClass.m @@ -0,0 +1,129 @@ +// $Id: ApModuleBaseClass.m,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#include "ApModuleBaseClass.h" +#include +#include "http_config.h" +#import +#import +#import +#include "ApacheServer.h" +#include "ApacheResourcePool.h" +#include "ApacheModule.h" +#include "ApacheRequest.h" + +@interface ApModuleBaseClass(Privates) + ++ (handler_rec *)apacheHandlerTable; ++ (command_rec *)apacheCommandTable; + +@end + +@implementation ApModuleBaseClass + ++ (void)setBundleHandler:(ApacheModule *)_handler { + [self subclassResponsibility:_cmd]; +} ++ (ApacheModule *)bundleHandler { + return [self subclassResponsibility:_cmd]; +} + ++ (void *)apacheModule { + ApacheModule *bundleHandler = [self bundleHandler]; + module *mod, *tmpl; + + if (bundleHandler == nil) { + NSLog(@"%s: missing bundle handler !!!", __PRETTY_FUNCTION__); + return NULL; + } + + mod = [self apacheModuleStructure]; + tmpl = [self apacheTemplateModule]; + + mod->cmds = [self apacheCommandTable]; + mod->handlers = [self apacheHandlerTable]; + + /* fill module based on handler reflection ... */ + + mod->init = + [bundleHandler respondsToSelector: + @selector(initializeModuleForServer:inPool:)] + ? tmpl->init : NULL; + + mod->create_dir_config = + [bundleHandler respondsToSelector: + @selector(createPerDirectoryConfigInPool:)] + ? tmpl->create_dir_config : NULL; + + mod->merge_dir_config = + [bundleHandler respondsToSelector: + @selector(mergePerDirectoryBaseConfig:withNewConfig:inPool:)] + ? tmpl->merge_dir_config : NULL; + + mod->create_server_config = + [bundleHandler respondsToSelector: + @selector(createPerServerConfig:inPool:)] + ? tmpl->create_server_config : NULL; + + mod->merge_server_config = + [bundleHandler respondsToSelector: + @selector(mergePerServerBaseConfig:withNewConfig:inPool:)] + ? tmpl->merge_server_config : NULL; + + mod->translate_handler = + [bundleHandler respondsToSelector:@selector(handleTranslationForRequest:)] + ? tmpl->translate_handler : NULL; + mod->ap_check_user_id = + [bundleHandler respondsToSelector:@selector(checkUserIdFromRequest:)] + ? tmpl->ap_check_user_id : NULL; + mod->auth_checker = + [bundleHandler respondsToSelector:@selector(checkAuthForRequest:)] + ? tmpl->auth_checker : NULL; + mod->access_checker = + [bundleHandler respondsToSelector:@selector(checkAccessForRequest:)] + ? tmpl->access_checker : NULL; + mod->type_checker = + [bundleHandler respondsToSelector:@selector(checkTypeForRequest:)] + ? tmpl->type_checker : NULL; + mod->logger = + [bundleHandler respondsToSelector:@selector(logRequest:)] + ? tmpl->logger : NULL; + + mod->fixer_upper = + [bundleHandler respondsToSelector:@selector(fixupRequest:)] + ? tmpl->fixer_upper : NULL; + + mod->header_parser = + [bundleHandler respondsToSelector:@selector(parseHeadersOfRequest:)] + ? tmpl->header_parser : NULL; + + mod->post_read_request = + [bundleHandler respondsToSelector:@selector(postProcessRequest:)] + ? tmpl->post_read_request : NULL; + + mod->child_init = + [bundleHandler respondsToSelector: + @selector(initializeChildProcessWithServer:inPool:)] + ? tmpl->child_init : NULL; + mod->child_exit = + [bundleHandler respondsToSelector: + @selector(exitChildProcessWithServer:inPool:)] + ? tmpl->child_exit : NULL; + + return mod; +} + +@end /* ApModuleBaseClass */ + +@implementation ApModuleBaseClass(SubclassOverrides) + ++ (void *)apacheTemplateModule { + return [self subclassResponsibility:_cmd]; +} ++ (void *)apacheModuleStructure { + return [self subclassResponsibility:_cmd]; +} ++ (void *)handleRequestStubFunction { + return [self subclassResponsibility:_cmd]; +} + +@end /* ApModuleBaseClass(SubclassOverrides) */ diff --git a/Recycler/mod_objc/ApTest.m b/Recycler/mod_objc/ApTest.m new file mode 100644 index 00000000..3940a2aa --- /dev/null +++ b/Recycler/mod_objc/ApTest.m @@ -0,0 +1,101 @@ +// $Id: ApTest.m,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#include "ApacheModule.h" +#import + +@interface ApTest : ApacheModule +@end + +#include "ApacheResourcePool.h" + +@implementation ApTest + +- (id)init { + //printf("INIT 0x%08X ..\n", (unsigned int)self); + return self; +} +- (void)dealloc { + //printf("DEALLOC 0x%08X ..\n", (unsigned int)self); + [super dealloc]; +} + +/* config commands */ + +- (id)configureDirectory_MyDirAlias:(NSString *)_fake:(NSString *)_real + directoryConfig:(id)_cfg + parameters:(ApacheCmdParms *)_params +{ + [self logWithFormat:@"MyDirAlias(%@,%@,config=%@)", _fake, _real, _cfg]; + [_cfg setObject:_real forKey:_fake]; + return nil; +} +- (id)configureServer_MyServerAlias:(NSString *)_fake:(NSString *)_real + parameters:(ApacheCmdParms *)_params +{ + [self logWithFormat:@"MyServerAlias(%@,%@)", _fake, _real]; + return nil; +} + +- (id)configureDirectory_PrintDirConfig:(NSString *)_fake + directoryConfig:(id)_cfg + parameters:(ApacheCmdParms *)_params +{ + [self logWithFormat:@"DIR: %@", _cfg]; + return nil; +} + +/* handlers */ + +- (int)handleTextHtmlRequest:(ApacheRequest *)_rq { + printf("%s ...\n", __PRETTY_FUNCTION__); + return ApacheDeclineRequest; +} +- (int)performApTestRequest:(ApacheRequest *)_rq { + printf("%s ...\n", __PRETTY_FUNCTION__); + return ApacheDeclineRequest; +} + +/* callbacks */ + +#if 0 +- (void)initializeModuleForServer:(ApacheServer *)_server + inPool:(ApacheResourcePool *)_pool +{ + [self debugWithFormat:@"init module for server %@", _server]; +} +#endif + +- (id)createPerDirectoryConfigInPool:(ApacheResourcePool *)_pool { + NSMutableDictionary *md; + + md = [[NSMutableDictionary alloc] initWithCapacity:128]; + [_pool releaseObject:md]; + return md; +} +- (id)mergePerDirectoryBaseConfig:(id)_base withNewConfig:(id)_new + inPool:(ApacheResourcePool *)_pool +{ + [self debugWithFormat:@"merge dir config %@ with %@ ..", + _base, _new]; + return _base; +} + +- (id)createPerServerConfig:(ApacheServer *)_server + inPool:(ApacheResourcePool *)_pool +{ + return [NSMutableDictionary dictionaryWithCapacity:128]; +} +- (id)mergePerServerBaseConfig:(id)_base withNewConfig:(id)_new + inPool:(ApacheResourcePool *)_pool +{ + [self debugWithFormat:@"merge server config %@ with %@ ..", + _base, _new]; + return nil; +} + +- (int)logRequest:(ApacheRequest *)_rq { + [self logWithFormat:@"REQUEST: %@", _rq]; + return ApacheDeclineRequest; +} + +@end /* ApTest */ diff --git a/Recycler/mod_objc/ApacheCmdParms.h b/Recycler/mod_objc/ApacheCmdParms.h new file mode 100644 index 00000000..433b52f0 --- /dev/null +++ b/Recycler/mod_objc/ApacheCmdParms.h @@ -0,0 +1,33 @@ +// $Id: ApacheCmdParms.h,v 1.1 2004/06/08 11:15:58 helge Exp $ + +#ifndef __ApacheCmdParms_H__ +#define __ApacheCmdParms_H__ + +#include + +@class ApacheResourcePool, ApacheServer; + +@interface ApacheCmdParms : ApacheObject +{ +} + +/* accessors */ + +- (void *)userInfo; + +/* Pool to allocate new storage in */ +- (ApacheResourcePool *)pool; + +/* + Pool for scratch memory; persists during + configuration, but wiped before the first + request is served... +*/ +- (ApacheResourcePool *)temporaryPool; + +/* Server_rec being configured for */ +- (ApacheServer *)server; + +@end + +#endif /* __ApacheCmdParms_H__ */ diff --git a/Recycler/mod_objc/ApacheCmdParms.m b/Recycler/mod_objc/ApacheCmdParms.m new file mode 100644 index 00000000..e88d4543 --- /dev/null +++ b/Recycler/mod_objc/ApacheCmdParms.m @@ -0,0 +1,66 @@ +// $Id: ApacheCmdParms.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheCmdParms.h" +#include "ApacheResourcePool.h" +#include "httpd.h" +#include "http_config.h" +#import + +@implementation ApacheCmdParms + +#define AP_HANDLE ((cmd_parms *)self->handle) + +- (void *)userInfo { + /* Argument to command from cmd_table */ + return AP_HANDLE->info; +} + +- (ApacheResourcePool *)pool { + ApacheResourcePool *pool; + + pool = [[ApacheResourcePool alloc] + initWithHandle:AP_HANDLE->pool freeWhenDone:NO]; + return AUTORELEASE(pool); +} +- (ApacheResourcePool *)temporaryPool { + ApacheResourcePool *pool; + + pool = [[ApacheResourcePool alloc] + initWithHandle:AP_HANDLE->temp_pool + freeWhenDone:NO]; + return AUTORELEASE(pool); +} + +- (ApacheServer *)server { + return [[[ApacheServer alloc] initWithHandle:AP_HANDLE->server] autorelease]; +} + +- (NSString *)path { + const unsigned char *c; + + if ((c = AP_HANDLE->path) == NULL) + return nil; + return [[[NSString alloc] initWithCString:c] autorelease]; +} + +/* description */ + +- (NSString *)description { + NSMutableString *ms; + id tmp; + + ms = [NSMutableString stringWithCapacity:256]; + [ms appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])]; + + [ms appendFormat:@" 0x%08X ui=0x%08X", self->handle, [self userInfo]]; + + if ((tmp = [self path])) + [ms appendFormat:@" path=%@", tmp]; + if ((tmp = [self server])) + [ms appendFormat:@" server=%@", tmp]; + + [ms appendString:@">"]; + return ms; +} + +@end /* ApacheCmdParms */ diff --git a/Recycler/mod_objc/ApacheConnection.h b/Recycler/mod_objc/ApacheConnection.h new file mode 100644 index 00000000..f2e8f61e --- /dev/null +++ b/Recycler/mod_objc/ApacheConnection.h @@ -0,0 +1,46 @@ +// $Id: ApacheConnection.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheConnection_H__ +#define __ApacheConnection_H__ + +#include "ApacheObject.h" + +@class NSString; +@class ApacheResourcePool, ApacheServer; + +@interface ApacheConnection : ApacheObject + +/* accessors */ + +- (ApacheResourcePool *)connectionPool; +- (ApacheServer *)server; +- (ApacheServer *)baseServer; + +/* Information about the connection itself */ + +- (int)childNumber; + +/* Who is the client? */ + +- (NSString *)remoteIP; +- (NSString *)remoteHost; +- (NSString *)remoteLogName; +- (NSString *)user; +- (NSString *)authorizationType; + +- (NSString *)localIP; +- (NSString *)localHost; + +- (BOOL)isAborted; + +- (BOOL)usesKeepAlive; +- (BOOL)doesNotUseKeepAlive; +- (BOOL)didUseKeepAlive; +- (int)numberOfKeepAlives; + +- (BOOL)isValidDoubleReverseDNS; +- (BOOL)isInvalidDoubleReverseDNS; + +@end + +#endif /* __ApacheConnection_H__ */ diff --git a/Recycler/mod_objc/ApacheConnection.m b/Recycler/mod_objc/ApacheConnection.m new file mode 100644 index 00000000..b7b102b8 --- /dev/null +++ b/Recycler/mod_objc/ApacheConnection.m @@ -0,0 +1,110 @@ +// $Id: ApacheConnection.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheConnection.h" +#import +#include "httpd.h" + +@implementation ApacheConnection +#define AP_HANDLE ((conn_rec *)self->handle) + +/* accessors */ + +- (ApacheResourcePool *)connectionPool { + return [ApacheResourcePool objectWithHandle:AP_HANDLE->pool]; +} +- (ApacheServer *)server { + return [ApacheServer objectWithHandle:AP_HANDLE->server]; +} +- (ApacheServer *)baseServer { + return [ApacheServer objectWithHandle:AP_HANDLE->base_server]; +} + +/* Information about the connection itself */ + +- (int)childNumber { + return AP_HANDLE->child_num; +} + +/* Who is the client? */ + +// struct sockaddr_in local_addr; +// struct sockaddr_in remote_addr; +- (NSString *)remoteIP { + return [NSString stringWithCString:AP_HANDLE->remote_ip]; +} +- (NSString *)remoteHost { + return [NSString stringWithCString:AP_HANDLE->remote_host]; +} +- (NSString *)remoteLogName { + return [NSString stringWithCString:AP_HANDLE->remote_logname]; +} +- (NSString *)user { + return [NSString stringWithCString:AP_HANDLE->user]; +} +- (NSString *)authorizationType { + return [NSString stringWithCString:AP_HANDLE->ap_auth_type]; +} + +- (NSString *)localIP { + return [NSString stringWithCString:AP_HANDLE->local_ip]; +} +- (NSString *)localHost { + return [NSString stringWithCString:AP_HANDLE->local_host]; +} + +- (BOOL)isAborted { + return AP_HANDLE->aborted ? YES : NO; +} +- (BOOL)usesKeepAlive { + return AP_HANDLE->keepalive == 1 ? YES : NO; +} +- (BOOL)doesNotUseKeepAlive { + return AP_HANDLE->keepalive == -1 ? YES : NO; +} +- (BOOL)didUseKeepAlive { + return AP_HANDLE->keptalive ? YES : NO; +} + +- (int)numberOfKeepAlives { + return AP_HANDLE->keepalives; +} + +- (BOOL)isValidDoubleReverseDNS { + return AP_HANDLE->double_reverse == 1 ? YES : NO; +} +- (BOOL)isInvalidDoubleReverseDNS { + return AP_HANDLE->double_reverse == -1 ? YES : NO; +} + +#undef AP_HANDLE + + +- (NSString *)description { + NSMutableString *ms; + id tmp; + + ms = [NSMutableString stringWithCapacity:128]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + [ms appendFormat:@" 0x%08X", self->handle]; + + if ([self isAborted]) [ms appendString:@" aborted"]; + if ([self usesKeepAlive]) [ms appendString:@" keepalive"]; + if ([self didUseKeepAlive]) [ms appendString:@" did-keepalive"]; + + if ([self numberOfKeepAlives] > 0) + [ms appendFormat:@" #keepalives=%i", [self numberOfKeepAlives]]; + + tmp = [self remoteIP]; + if ([tmp length] > 0) [ms appendFormat:@" remoteIP=%@", tmp]; + + tmp = [self user]; + if ([tmp length] > 0) [ms appendFormat:@" user=%@", tmp]; + + tmp = [self authorizationType]; + if ([tmp length] > 0) [ms appendFormat:@" auth=%@", tmp]; + + [ms appendString:@">"]; + return ms; +} + +@end /* ApacheConnection */ diff --git a/Recycler/mod_objc/ApacheModule.h b/Recycler/mod_objc/ApacheModule.h new file mode 100644 index 00000000..cb3402dd --- /dev/null +++ b/Recycler/mod_objc/ApacheModule.h @@ -0,0 +1,116 @@ +// $Id: ApacheModule.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheModule_H__ +#define __ApacheModule_H__ + +#import + +@class NSString; +@class ApacheCmdParms, ApacheResourcePool, ApacheServer; + +@interface ApacheModule : NSObject + +/* return the usage string for config commands */ +- (NSString *)usageForConfigSelector:(SEL)_selector; + +/* logging */ + +- (void)logWithFormat:(NSString *)_format, ...; +- (void)debugWithFormat:(NSString *)_format, ...; + +@end + +@class ApacheRequest; + +/* + Note: Modules should not rely on the order in which create_server_config + and create_dir_config are called. +*/ + +@interface ApacheModule(ConfigOperations) + +- (id)createPerDirectoryConfigInPool:(ApacheResourcePool *)_pool; +- (id)mergePerDirectoryBaseConfig:(id)_base withNewConfig:(id)_new + inPool:(ApacheResourcePool *)_pool; + +- (id)createPerServerConfig:(ApacheServer *)_server + inPool:(ApacheResourcePool *)_pool; +- (id)mergePerServerBaseConfig:(id)_base withNewConfig:(id)_new + inPool:(ApacheResourcePool *)_pool; + +/* + -initializeModuleForServer:inPool: occurs after config parsing, but + before any children are forked. +*/ +- (void)initializeModuleForServer:(ApacheServer *)_server + inPool:(ApacheResourcePool *)_pool; + +@end + +/* Hooks for getting into the middle of server ops ... */ + +extern int ApacheDeclineRequest; +extern int ApacheHandledRequest; + +@interface ApacheModule(ServerOperations) + +/* translate_handler --- translate URI to filename */ +- (int)handleTranslationForRequest:(ApacheRequest *)_req; + +/* + access_checker --- check access by host address, etc. All of these + run; if all decline, that's still OK. +*/ +- (int)checkAccessForRequest:(ApacheRequest *)_req; + +/* check_user_id --- get and validate user id from the HTTP request */ +- (int)checkUserIdFromRequest:(ApacheRequest *)_req; + +/* + auth_checker --- see if the user (from check_user_id) is OK *here*. + If all of *these* decline, the request is rejected + (as a SERVER_ERROR, since the module which was + supposed to handle this was configured wrong). +*/ +- (int)checkAuthForRequest:(ApacheRequest *)_req; + +/* + type_checker --- Determine MIME type of the requested entity; + sets content_type, _encoding and _language fields. +*/ +- (int)checkTypeForRequest:(ApacheRequest *)_req; + +/* logger --- log a transaction. */ +- (int)logRequest:(ApacheRequest *)_req; + +- (int)fixupRequest:(ApacheRequest *)_req; +- (int)parseHeadersOfRequest:(ApacheRequest *)_req; + +/* + post_read_request --- run right after read_request or internal_redirect, + and not run during any subrequests. +*/ +- (int)postProcessRequest:(ApacheRequest *)_req; + +@end + +/* Regardless of the model the server uses for managing "units of + * execution", i.e. multi-process, multi-threaded, hybrids of those, + * there is the concept of a "heavy weight process". That is, a + * process with its own memory space, file spaces, etc. This method, + * child_init, is called once for each heavy-weight process before + * any requests are served. Note that no provision is made yet for + * initialization per light-weight process (i.e. thread). The + * parameters passed here are the same as those passed to the global + * init method above. + */ +@interface ApacheModule(ForkOperations) + +- (void)initializeChildProcessWithServer:(ApacheServer *)_server + inPool:(ApacheResourcePool *)_pool; +- (void)exitChildProcessWithServer:(ApacheServer *)_server + inPool:(ApacheResourcePool *)_pool; + +@end + +#endif /* __ApacheModule_H__ */ diff --git a/Recycler/mod_objc/ApacheModule.m b/Recycler/mod_objc/ApacheModule.m new file mode 100644 index 00000000..76e254a0 --- /dev/null +++ b/Recycler/mod_objc/ApacheModule.m @@ -0,0 +1,59 @@ +// $Id: ApacheModule.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheModule.h" +#include "ApacheCmdParms.h" +#include "ApacheResourcePool.h" +#import +#include "httpd.h" + +int ApacheDeclineRequest = DECLINED; +int ApacheHandledRequest = OK; + +@implementation ApacheModule + +- (NSString *)usageForConfigSelector:(SEL)_selector { + return nil; +} + +/* logging */ + +- (void)logWithFormat:(NSString *)_format, ... { + NSString *value = nil; + va_list ap; + + va_start(ap, _format); + value = [NSString stringWithFormat:_format arguments:ap]; + va_end(ap); + +#if DEBUG + printf("|0x%08X| %s\n", (unsigned int)self, [[value description] cString]); +#else + NSLog(@"|0x%08X| %@", self, value); +#endif +} +- (void)debugWithFormat:(NSString *)_format, ... { + static char showDebug = 2; + NSString *value = nil; + va_list ap; + + if (showDebug == 2) { +#if 0 + showDebug = [WOApplication isDebuggingEnabled] ? 1 : 0; +#endif + } + + if (showDebug) { + va_start(ap, _format); + value = [NSString stringWithFormat:_format arguments:ap]; + va_end(ap); + +#if DEBUG + printf("|0x%08X|D %s\n", (unsigned int)self, + [[value description] cString]); +#else + NSLog(@"|0x%08X|D %@", self, value); +#endif + } +} + +@end /* ApacheModule */ diff --git a/Recycler/mod_objc/ApacheObject.h b/Recycler/mod_objc/ApacheObject.h new file mode 100644 index 00000000..93f1df7a --- /dev/null +++ b/Recycler/mod_objc/ApacheObject.h @@ -0,0 +1,27 @@ +// $Id: ApacheObject.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheObject_H__ +#define __ApacheObject_H__ + +#import + +@interface ApacheObject : NSObject +{ + void *handle; + BOOL freeWhenDone; // if yes, call destroyHandle in -dealloc +} + ++ (id)objectWithHandle:(void *)_handle; + +- (id)initWithHandle:(void *)_handle freeWhenDone:(BOOL)_flag; // designated +- (id)initWithHandle:(void *)_handle; // freeWhenDone:NO + +/* destroy a handle (needs to be overidden by subclasses) */ +- (void)destroyHandle; + +/* accessors */ +- (void *)handle; + +@end + +#endif /* __ApacheObject_H__ */ diff --git a/Recycler/mod_objc/ApacheObject.m b/Recycler/mod_objc/ApacheObject.m new file mode 100644 index 00000000..53a40c1b --- /dev/null +++ b/Recycler/mod_objc/ApacheObject.m @@ -0,0 +1,79 @@ +// $Id: ApacheObject.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheObject.h" +#import + +@implementation ApacheObject + +static NSMapTable *proxyRegistry = NULL; // THREAD + ++ (void)initialize { + if (proxyRegistry == NULL) { + proxyRegistry = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, + 128); + } +} + ++ (id)objectWithHandle:(void *)_handle { + id proxy; + + if (_handle == NULL) return nil; + + if ((proxy = NSMapGet(proxyRegistry, _handle))) + return proxy; + + return [[[self alloc] initWithHandle:_handle freeWhenDone:NO] autorelease]; +} + +- (id)initWithHandle:(void *)_handle freeWhenDone:(BOOL)_flag { + if (_handle == NULL) { + RELEASE(self); + return nil; + } + + self->handle = _handle; + self->freeWhenDone = _flag; + + NSMapInsert(proxyRegistry, _handle, self); + + return self; +} +- (id)initWithHandle:(void *)_handle { + return [self initWithHandle:_handle freeWhenDone:NO]; +} +- (id)init { + return [self initWithHandle:NULL freeWhenDone:NO]; +} + +- (void)dealloc { + if (self->handle) { + NSMapRemove(proxyRegistry, self->handle); + + if (self->freeWhenDone) { + [self destroyHandle]; + self->handle = NULL; + } + } + [super dealloc]; +} + +- (void)destroyHandle { + [self subclassResponsibility:_cmd]; +} + +/* accessors */ + +- (void *)handle { + return self->handle; +} + +/* description */ + +- (NSString *)description { + return [NSString stringWithFormat:@"<0x%08X[%@]: apache=0x%08X>", + self, NSStringFromClass([self class]), + self->handle]; +} + +@end /* ApacheObject */ diff --git a/Recycler/mod_objc/ApacheRequest.h b/Recycler/mod_objc/ApacheRequest.h new file mode 100644 index 00000000..c9819066 --- /dev/null +++ b/Recycler/mod_objc/ApacheRequest.h @@ -0,0 +1,200 @@ +// $Id: ApacheRequest.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheRequest_H__ +#define __ApacheRequest_H__ + +#include "ApacheObject.h" +#include + +@class NSString, NSDate, NSData; +@class ApacheResourcePool, ApacheConnection, ApacheServer; +@class ApacheTable; + +/* + An Objective-C wrapper for the Apache request structure. + + Note: the Apache request itself is allocated from it's + request resource pool ! +*/ + +@interface ApacheRequest : ApacheObject +{ +} + +/* accessors */ + +- (ApacheResourcePool *)requestPool; +- (ApacheConnection *)connection; +- (ApacheServer *)server; + +/* requests */ + +/* + If we wind up getting redirected, pointer to the request we redirected to. +*/ +- (ApacheRequest *)redirectToRequest; + +/* If this is an internal redirect, pointer to where we redirected *from*. */ +- (ApacheRequest *)redirectFromRequest; + +/* + If this is a sub_request (see request.h) pointer back to the main request. +*/ +- (ApacheRequest *)mainRequest; + +/* + Info about the request itself... we begin with stuff that only + protocol.c should ever touch... +*/ +- (NSString *)firstRequestLine; +- (BOOL)isBackwards; +- (BOOL)isHeadRequest; +- (NSString *)protocol; +- (int)protocolNumber; +- (NSString *)hostName; +- (NSDate *)requestTime; +- (NSString *)statusLine; +- (int)status; + +/* + Request method, two ways; also, protocol, etc.. Outside of protocol.c, + look, but don't touch. +*/ +- (NSString *)method; +- (int)methodNumber; ++ (int)numberForMethod:(NSString *)_method; + +/* modifying the allowed-method set */ +- (void)allowMethodNumber:(int)_num; +- (BOOL)isMethodNumberAllowed:(int)_num; + +- (unsigned int)bytesSent; +- (NSDate *)lastModified; + +/* HTTP/1.1 connection-level features */ + +- (BOOL)isChunkedSending; +- (int)byteRangeCount; +- (NSString *)byteRangeBoundary; +- (NSString *)range; +- (unsigned int)contentLength; + +- (unsigned int)numberOfRemainingBytes; +- (unsigned int)numberOfReadBytes; +- (BOOL)isChunkedReceiving; +- (BOOL)isExpecting100; + +/* MIME tables */ + +- (ApacheTable *)headersIn; +- (ApacheTable *)headersOut; +- (ApacheTable *)errorHeadersOut; +- (ApacheTable *)subprocessEnvironment; +- (ApacheTable *)notes; + +/* content-info */ + +- (void)setContentType:(NSString *)_ctype; +- (NSString *)contentType; +- (void)setContentEncoding:(NSString *)_cencoding; +- (NSString *)contentEncoding; +- (void)setContentLanguage:(NSString *)_clanguage; +- (NSString *)contentLanguage; +- (NSArray *)contentLanguages; +- (NSString *)vlistValidator; + +- (void)setHandler:(NSString *)_value; +- (NSString *)handler; + +- (BOOL)noCache; +- (BOOL)noLocalCopy; + +/* + What object is being requested (either directly, or via include + or content-negotiation mapping). +*/ +- (NSString *)unparsedURI; +- (NSString *)uri; +- (NSString *)filename; +- (NSString *)pathInfo; +- (NSString *)queryArgs; +- (NSString *)casePreservedFilename; + +- (void)parseURI:(NSString *)_uri; + +/* sub-requests */ + +- (ApacheRequest *)subRequestLookupURI:(NSString *)_newfile; +- (ApacheRequest *)subRequestLookupURI:(NSString *)_newfile + method:(NSString *)_method; +- (ApacheRequest *)subRequestLookupFile:(NSString *)_newfile; + +/* operations */ + +- (int)runSubRequest; +- (void)destroySubRequest; + +- (void)internalRedirect:(NSString *)_uri; +- (void)internalRedirectHandler:(NSString *)_uri; + +- (int)someAuthorizationRequired; +- (BOOL)isInitialRequest; + +- (NSDate *)updateModificationTime:(NSDate *)_date; + +/* sending headers */ + +- (void)sendBasicHttpHeader; +- (void)sendHttpHeader; +- (int)sendHttpTrace; +- (int)sendHttpOptions; + +/* Finish up stuff after a request */ +- (void)finalizeRequestProtocol; + +- (void)sendErrorResponse; +- (void)sendErrorResponseWithRecursiveFailStatus:(int)_state; + +/* modifying headers */ + +- (int)setContentLength:(unsigned int)_len; +- (int)setKeepAlive; +- (NSDate *)rationalizeModificationTime:(NSDate *)_mtime; +- (NSString *)makeETag:(BOOL)_forceWeak; +- (void)setETag; +- (void)setLastModified; +- (int)meetsConditions; + +/* sending content */ + +- (long)sendFile:(FILE *)_file; +- (long)sendFile:(FILE *)_file length:(long)_len; +- (unsigned int)sendMMap:(void *)_mm + offset:(unsigned int)_off length:(unsigned int)_len; + +- (int)rputc:(int)_c; +- (int)rputs:(const char *)_cstr; +- (int)rwrite:(const void *)_buf length:(unsigned int)_len; +- (int)rflush; +- (int)rwriteData:(NSData *)_data; + +/* Reading a block of data from the client connection (e.g., POST arg) */ + +- (int)setupClientBlock:(int)_readPolicy; +- (int)shouldClientBlock; +- (long)getClientBlock:(char *)_buffer length:(int)_bufsiz; +- (int)discardRequestBody; + +/* Sending a byterange */ + +- (int)setByteRange; + +/* basic authentication */ + +- (void)noteAuthFailure; +- (void)noteBasicAuthFailure; +- (int)getBasicAuthPassword:(const char **)_pwd; + +@end + +#endif /* __ApacheRequest_H__ */ diff --git a/Recycler/mod_objc/ApacheRequest.m b/Recycler/mod_objc/ApacheRequest.m new file mode 100644 index 00000000..c4d17cde --- /dev/null +++ b/Recycler/mod_objc/ApacheRequest.m @@ -0,0 +1,457 @@ +// $Id: ApacheRequest.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheRequest.h" +#import +#include "httpd.h" +#include "http_request.h" +#include "http_protocol.h" + +#define ApCharSetAccessor(_field, _val_) \ + {\ + char *val;\ + unsigned len;\ + \ + len = [_val_ cStringLength];\ + val = ap_palloc(AP_HANDLE->pool, len + 1);\ + [_val_ getCString:val];\ + val[len] = '\0';\ + \ + AP_HANDLE->_field = val;\ + } + +@implementation ApacheRequest +#define AP_HANDLE ((request_rec *)self->handle) + +/* accessors */ + +- (ApacheResourcePool *)requestPool { + return [ApacheResourcePool objectWithHandle:AP_HANDLE->pool]; +} +- (ApacheConnection *)connection { + return [ApacheConnection objectWithHandle:AP_HANDLE->connection]; +} +- (ApacheServer *)server { + return [ApacheServer objectWithHandle:AP_HANDLE->server]; +} + +/* requests */ + +- (ApacheRequest *)redirectToRequest { + return [ApacheRequest objectWithHandle:AP_HANDLE->next]; +} +- (ApacheRequest *)redirectFromRequest { + return [ApacheRequest objectWithHandle:AP_HANDLE->prev]; +} +- (ApacheRequest *)mainRequest { + return [ApacheRequest objectWithHandle:AP_HANDLE->main]; +} + +/* + Info about the request itself... we begin with stuff that only + protocol.c should ever touch... +*/ + +- (NSString *)firstRequestLine { + return [NSString stringWithCString:AP_HANDLE->the_request]; +} +- (BOOL)isBackwards { + return AP_HANDLE->assbackwards ? YES : NO; +} +/* proxy ? */ +- (BOOL)isHeadRequest { + return AP_HANDLE->header_only ? YES : NO; +} + +- (NSString *)protocol { + return [NSString stringWithCString:AP_HANDLE->protocol]; +} +- (int)protocolNumber { + return AP_HANDLE->proto_num; +} + +- (NSString *)hostName { + return [NSString stringWithCString:AP_HANDLE->hostname]; +} + +- (NSDate *)requestTime { + return [NSDate dateWithTimeIntervalSince1970:AP_HANDLE->request_time]; +} + +- (NSString *)statusLine { + return [NSString stringWithCString:AP_HANDLE->status_line]; +} +- (int)status { + return AP_HANDLE->status; +} + +/* + Request method, two ways; also, protocol, etc.. Outside of protocol.c, + look, but don't touch. +*/ +- (NSString *)method { + return [NSString stringWithCString:AP_HANDLE->method]; +} +- (int)methodNumber { + return AP_HANDLE->method_number; +} ++ (int)numberForMethod:(NSString *)_method { + return ap_method_number_of([_method cString]); +} + +- (void)allowMethodNumber:(int)_num { + AP_HANDLE->allowed |= (1 << _num); +} +- (BOOL)isMethodNumberAllowed:(int)_num { + return (AP_HANDLE->allowed & (1 << _num)) ? YES : NO; +} + +- (unsigned int)bytesSent { + return AP_HANDLE->bytes_sent; +} +- (NSDate *)lastModified { + return [NSDate dateWithTimeIntervalSince1970:AP_HANDLE->mtime]; +} + +/* HTTP/1.1 connection-level features */ + +- (BOOL)isChunkedSending { + return AP_HANDLE->chunked ? YES : NO; +} +- (int)byteRangeCount { + return AP_HANDLE->byterange; +} +- (NSString *)byteRangeBoundary { + return [NSString stringWithCString:AP_HANDLE->boundary]; +} +- (NSString *)range { + return [NSString stringWithCString:AP_HANDLE->range]; +} +- (unsigned int)contentLength { + return AP_HANDLE->clength; +} + +- (unsigned int)numberOfRemainingBytes { + return AP_HANDLE->remaining; +} +- (unsigned int)numberOfReadBytes { + return AP_HANDLE->read_length; +} +- (BOOL)isChunkedReceiving { + return AP_HANDLE->read_chunked ? YES : NO; +} +- (BOOL)isExpecting100 { + return AP_HANDLE->expecting_100 ? YES : NO; +} + +/* + MIME header environments, in and out. Also, an array containing + environment variables to be passed to subprocesses, so people can + write modules to add to that environment. + + The difference between headers_out and err_headers_out is that the + latter are printed even on error, and persist across internal redirects + (so the headers printed for ErrorDocument handlers will have them). + + The 'notes' table is for notes from one module to another, with no + other set purpose in mind... +*/ + +- (ApacheTable *)headersIn { + return [ApacheTable objectWithHandle:AP_HANDLE->headers_in]; +} +- (ApacheTable *)headersOut { + return [ApacheTable objectWithHandle:AP_HANDLE->headers_out]; +} +- (ApacheTable *)errorHeadersOut { + return [ApacheTable objectWithHandle:AP_HANDLE->err_headers_out]; +} +- (ApacheTable *)subprocessEnvironment { + return [ApacheTable objectWithHandle:AP_HANDLE->subprocess_env]; +} +- (ApacheTable *)notes { + return [ApacheTable objectWithHandle:AP_HANDLE->notes]; +} + +/* + content_type, handler, content_encoding, content_language, and all + content_languages MUST be lowercased strings. They may be pointers + to static strings; they should not be modified in place. +*/ + +- (void)setContentType:(NSString *)_ctype { + _ctype = [_ctype lowercaseString]; + ApCharSetAccessor(content_type, _ctype); +} +- (NSString *)contentType { + return [NSString stringWithCString:AP_HANDLE->content_type]; +} + +- (void)setContentEncoding:(NSString *)_cencoding { + _cencoding = [_cencoding lowercaseString]; + ApCharSetAccessor(content_encoding, _cencoding); +} +- (NSString *)contentEncoding { + return [NSString stringWithCString:AP_HANDLE->content_encoding]; +} + +- (void)setContentLanguage:(NSString *)_clanguage { + _clanguage = [_clanguage lowercaseString]; + ApCharSetAccessor(content_language, _clanguage); +} +- (NSString *)contentLanguage { + return [NSString stringWithCString:AP_HANDLE->content_language]; +} + +- (NSString *)vlistValidator { + return [NSString stringWithCString:AP_HANDLE->vlist_validator]; +} + +- (NSArray *)contentLanguages { + // array_header *content_languages; /* array of (char*) */ + + return [self notImplemented:_cmd]; +} + +- (void)setHandler:(NSString *)_value { + ApCharSetAccessor(handler, _value); +} +- (NSString *)handler { + return [NSString stringWithCString:AP_HANDLE->handler]; +} + +- (BOOL)noCache { + return AP_HANDLE->no_cache ? YES : NO; +} +- (BOOL)noLocalCopy { + return AP_HANDLE->no_local_copy ? YES : NO; +} + +/* + What object is being requested (either directly, or via include + or content-negotiation mapping). +*/ +- (NSString *)unparsedURI { + return [NSString stringWithCString:AP_HANDLE->unparsed_uri]; +} +- (NSString *)uri { + return [NSString stringWithCString:AP_HANDLE->uri]; +} +- (NSString *)filename { + return [NSString stringWithCString:AP_HANDLE->filename]; +} +- (NSString *)pathInfo { + return [NSString stringWithCString:AP_HANDLE->path_info]; +} +- (NSString *)queryArgs { + return [NSString stringWithCString:AP_HANDLE->args]; +} +// finfo, parse_uri + +- (NSString *)casePreservedFilename { + return [NSString stringWithCString:AP_HANDLE->case_preserved_filename]; +} + +- (void)parseURI:(NSString *)_uri { + ap_parse_uri(AP_HANDLE, [_uri cString]); +} + +/* sub-requests */ + +- (ApacheRequest *)subRequestLookupURI:(NSString *)_newfile { + request_rec *sr; + sr = ap_sub_req_lookup_uri([_newfile cString], AP_HANDLE); + return [ApacheRequest objectWithHandle:sr]; +} +- (ApacheRequest *)subRequestLookupURI:(NSString *)_newfile + method:(NSString *)_method +{ + request_rec *sr; + sr = ap_sub_req_method_uri([_method cString], [_newfile cString], AP_HANDLE); + return [ApacheRequest objectWithHandle:sr]; +} +- (ApacheRequest *)subRequestLookupFile:(NSString *)_newfile { + request_rec *sr; + sr = ap_sub_req_lookup_file([_newfile cString], AP_HANDLE); + return [ApacheRequest objectWithHandle:sr]; +} + +/* operations */ + +- (int)runSubRequest { + return ap_run_sub_req(AP_HANDLE); +} +- (void)destroySubRequest { + ap_destroy_sub_req(AP_HANDLE); +} + +- (void)internalRedirect:(NSString *)_uri { + ap_internal_redirect([_uri cString], AP_HANDLE); +} +- (void)internalRedirectHandler:(NSString *)_uri { + ap_internal_redirect_handler([_uri cString], AP_HANDLE); +} + +- (int)someAuthorizationRequired { + return ap_some_auth_required(AP_HANDLE); +} +- (BOOL)isInitialRequest { + return ap_is_initial_req(AP_HANDLE); +} + +- (NSDate *)updateModificationTime:(NSDate *)_date { + return [NSDate dateWithTimeIntervalSince1970: + ap_update_mtime(AP_HANDLE, [_date timeIntervalSince1970])]; +} + +/* sending headers */ + +- (void)sendBasicHttpHeader { + ap_basic_http_header(AP_HANDLE); +} +- (void)sendHttpHeader { + ap_send_http_header(AP_HANDLE); +} +- (int)sendHttpTrace { + return ap_send_http_trace(AP_HANDLE); +} +- (int)sendHttpOptions { + return ap_send_http_options(AP_HANDLE); +} + +- (void)finalizeRequestProtocol { + ap_finalize_request_protocol(AP_HANDLE); +} + +- (void)sendErrorResponse { + [self sendErrorResponseWithRecursiveFailStatus:500]; +} +- (void)sendErrorResponseWithRecursiveFailStatus:(int)_state { + ap_send_error_response(AP_HANDLE, _state); +} + +/* modifying headers */ + +- (int)setContentLength:(unsigned int)_len { + return ap_set_content_length(AP_HANDLE, _len); +} +- (int)setKeepAlive { + return ap_set_keepalive(AP_HANDLE); +} +- (NSDate *)rationalizeModificationTime:(NSDate *)_mtime { + time_t t; + t = ap_rationalize_mtime(AP_HANDLE, [_mtime timeIntervalSince1970]); + return [NSDate dateWithTimeIntervalSince1970:t]; +} +- (NSString *)makeETag:(BOOL)_forceWeak { + return [NSString stringWithCString:ap_make_etag(AP_HANDLE, _forceWeak)]; +} +- (void)setETag { + ap_set_etag(AP_HANDLE); +} +- (void)setLastModified { + ap_set_last_modified(AP_HANDLE); +} +- (int)meetsConditions { + return ap_meets_conditions(AP_HANDLE); +} + +/* sending content */ + +- (long)sendFile:(FILE *)_file { + return ap_send_fd(_file, AP_HANDLE); +} +- (long)sendFile:(FILE *)_file length:(long)_len { + return ap_send_fd_length(_file, AP_HANDLE, _len); +} +- (unsigned int)sendMMap:(void *)_mm + offset:(unsigned int)_off length:(unsigned int)_len +{ + return ap_send_mmap(_mm, AP_HANDLE, _off, _len); +} + +- (int)rputc:(int)_c { + return ap_rputc(_c, AP_HANDLE); +} +- (int)rputs:(const char *)_cstr { + return ap_rputs(_cstr, AP_HANDLE); +} +- (int)rwrite:(const void *)_buf length:(unsigned int)_len { + return ap_rwrite(_buf, _len, AP_HANDLE); +} +- (int)rflush { + return ap_rflush(AP_HANDLE); +} + +- (int)rwriteData:(NSData *)_data { + return ap_rwrite([_data bytes], [_data length], AP_HANDLE); +} + +/* Reading a block of data from the client connection (e.g., POST arg) */ + +- (int)setupClientBlock:(int)_readPolicy { + return ap_setup_client_block(AP_HANDLE, _readPolicy); +} +- (int)shouldClientBlock { + return ap_should_client_block(AP_HANDLE); +} +- (long)getClientBlock:(char *)_buffer length:(int)_bufsiz { + return ap_get_client_block(AP_HANDLE, _buffer, _bufsiz); +} +- (int)discardRequestBody { + return ap_discard_request_body(AP_HANDLE); +} + +/* Sending a byterange */ + +- (int)setByteRange { + return ap_set_byterange(AP_HANDLE); +} +// ap_each_byterange(request_rec *r, long *offset, long *length); + +/* basic authentication */ + +- (void)noteAuthFailure { + ap_note_auth_failure(AP_HANDLE); +} +- (void)noteBasicAuthFailure { + ap_note_basic_auth_failure(AP_HANDLE); +} +- (int)getBasicAuthPassword:(const char **)_pwd { + return ap_get_basic_auth_pw(AP_HANDLE, _pwd); +} + +#undef AP_HANDLE + +- (NSString *)description { + NSMutableString *ms; + id tmp; + + ms = [NSMutableString stringWithCapacity:128]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + [ms appendFormat:@" 0x%08X", self->handle]; + + if ([self isHeadRequest]) [ms appendString:@" head"]; + + tmp = [self method]; + if ([tmp length] > 0) [ms appendFormat:@" %@", tmp]; + tmp = [self uri]; + if ([tmp length] > 0) [ms appendFormat:@" uri='%@'", tmp]; + + if ([self isChunkedReceiving]) [ms appendString:@" in-chunked"]; + if ([self isChunkedSending]) [ms appendString:@" out-chunked"]; + + if ([self numberOfReadBytes] > 0) + [ms appendFormat:@" bytesRead=%i", [self numberOfReadBytes]]; + if ([self numberOfRemainingBytes] > 0) + [ms appendFormat:@" remainingBytes=%i", [self numberOfRemainingBytes]]; + if ([self bytesSent] > 0) + [ms appendFormat:@" bytesSent=%i", [self bytesSent]]; + + if ((tmp = [self connection])) + [ms appendFormat:@" con=%@", tmp]; + + [ms appendString:@">"]; + return ms; +} + +@end /* ApacheRequest */ diff --git a/Recycler/mod_objc/ApacheResourcePool.h b/Recycler/mod_objc/ApacheResourcePool.h new file mode 100644 index 00000000..b1593b0e --- /dev/null +++ b/Recycler/mod_objc/ApacheResourcePool.h @@ -0,0 +1,134 @@ +// $Id: ApacheResourcePool.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheResourcePool_H__ +#define __ApacheResourcePool_H__ + +#include "ApacheObject.h" +#include + +/* + Note: Apache resource pools are some kind of mixture between an + FoundationNSAutoreleasePool and a Foundation NSZone. You should mix + up Apache resource pools and autorelease pools ! + + Objective-C support: ApacheResourcePool can register release + callbacks for Foundation objects. + Eg: + ApacheResourcePool *p; + id s = [[NSString alloc] initWithCString:"blah"]; + [p releaseObject:s]; + + This will release the string (but not necessarily -dealloc !!!) if the + resource pool is freed by Apache. + + Most commonly used Apache resource pools (info take from API notes): + + permanent-pool: + - the "root" pool + + pconf + - subpool of permanent-pool + - created at the beginning of the config cycle + - exists until the server is restarted or terminated + - passed to all config routines via [cmd pool] or inPool:pool + - passed to the module init function + + ptemp + - subpool of permanent-pool + - created at the beginning of the config cycle + - exists until the end of the config parsing + - passed to config routines via [cmd temporaryPool] + + pchild + - subpool of permanent-pool + - created when a child is forked + - exists until child exits + - passedto -initializeChildProcessWithServer:inPool: and + -exitChildProcessWithServer:inPool: + + ptrans + - subpool of permanent-pool + - created by child before going into the accept loop + - passed in with [connection pool] + + r->pool + - for the main request a subpool of ptrans + for sub requests a subpool of the parent request pool + - exist until the end of the processing of the request + - note: the request itself is allocated from this pool !! +*/ + +@interface ApacheResourcePool : ApacheObject +{ +} + +- (id)makeSubPool; + +/* Clearing out EVERYTHING in an pool... destroys any sub-pools */ +- (void)clearPool; + +- (BOOL)isAncestorOf:(ApacheResourcePool *)_pool; + +/* stats */ + +- (unsigned int)bytesInPool; ++ (unsigned int)bytesInFreeBlocks; + +/* memory blocks */ + +- (void *)malloc:(unsigned)size; +- (void *)mallocAtomic:(unsigned)size; +- (void *)calloc:(unsigned)numElems byteSize:(unsigned)byteSize; +- (void *)callocAtomic:(unsigned)numElems byteSize:(unsigned)byteSize; + +- (void *)realloc:(void*)pointer size:(unsigned)size; +- (void)freePointer:(void *)pointer; + +/* string allocations */ + +- (unsigned char *)strdup:(const unsigned char *)_cstr; +- (unsigned char *)strdup:(const unsigned char *)_cstr length:(unsigned)_l; +- (unsigned char *)strcat:(const unsigned char *)_cstr; +- (unsigned char *)pvsprintf:(const unsigned char *)_fmt arguments:(va_list)va; + +/* file allocations */ + +- (FILE *)openFile:(NSString *)_name mode:(NSString *)_mode; +- (FILE *)openFD:(int)_fd mode:(NSString *)_mode; +- (int)popenf:(NSString *)_name flag:(int)_flg mode:(int)_mode; + +- (void)closeFile:(FILE *)_file; +- (void)pclosef:(int)_fd; +#ifdef WIN32 +- (void)closeHandle:(HANDLE)_h; +#endif + +- (void)noteCleanUpsForFile:(FILE *)_file; +- (void)noteCleanUpsForFD:(int)_fd; +#ifdef WIN32 +- (void)noteCleanUpsForHandle:(HANDLE)_h; +#endif +- (void)killCleanUpsForFD:(int)_fd; + +/* process management */ + +/* + Preparing for exec() --- close files, etc., but *don't* flush I/O + buffers, *don't* wait for subprocesses, and *don't* free any memory. +*/ ++ (void)cleanUpForExec; + +/* Objective-C objects */ + +- (void)releaseObject:(id)_object; +- (void)unreleaseObject:(id)_object; + +@end + +@interface NSObject(PoolRelease) + +- (void)cleanupForApacheExec; /* called before exec() */ + +@end + +#endif /* __ApacheResourcePool_H__ */ diff --git a/Recycler/mod_objc/ApacheResourcePool.m b/Recycler/mod_objc/ApacheResourcePool.m new file mode 100644 index 00000000..39657b6f --- /dev/null +++ b/Recycler/mod_objc/ApacheResourcePool.m @@ -0,0 +1,179 @@ +// $Id: ApacheResourcePool.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheResourcePool.h" +#include "httpd.h" +#include "ap_alloc.h" +#include + +@implementation ApacheResourcePool + +- (void)destroyHandle { + if (self->handle) { + ap_destroy_pool(self->handle); + self->handle = NULL; + } +} +- (id)makeSubPool { + ap_pool *p; + + if (self->handle == NULL) + return nil; + + if ((p = ap_make_sub_pool(self->handle)) == NULL) + return nil; + + return [[[ApacheResourcePool alloc] + initWithHandle:p freeWhenDone:YES] + autorelease]; +} +- (void)clearPool { + if (self->handle) ap_clear_pool(self->handle); +} + +- (BOOL)isAncestorOf:(ApacheResourcePool *)_pool { +#ifdef POOL_DEBUG + if (_pool == NULL) return NO; + if (self->handle == NULL) return NO; + + return ap_pool_is_ancestor(self->handle, _pool) ? YES : NO; +#else + return NO; +#endif +} + +/* stats */ + +- (unsigned int)bytesInPool { + if (self->handle == NULL) return 0; + return ap_bytes_in_pool(self->handle); +} ++ (unsigned int)bytesInFreeBlocks { + return ap_bytes_in_free_blocks(); +} + +/* memory blocks */ + +- (void *)malloc:(unsigned)size { + if (self->handle == NULL) return NULL; + return ap_palloc(self->handle, size); +} +- (void *)mallocAtomic:(unsigned)size { + if (self->handle == NULL) return NULL; + return ap_palloc(self->handle, size); +} +- (void *)calloc:(unsigned)numElems byteSize:(unsigned)byteSize { + if (self->handle == NULL) return NULL; + return ap_pcalloc(self->handle, byteSize * numElems); +} +- (void *)callocAtomic:(unsigned)numElems byteSize:(unsigned)byteSize { + if (self->handle == NULL) return NULL; + return ap_pcalloc(self->handle, byteSize * numElems); +} + +- (void *)realloc:(void*)pointer size:(unsigned)size { + return NULL; +} +- (void)freePointer:(void *)pointer { +} + +/* string allocations */ + +- (unsigned char *)strdup:(const unsigned char *)_cstr { + if (self->handle == NULL) return NULL; + return ap_pstrdup(self->handle, _cstr); +} +- (unsigned char *)strdup:(const unsigned char *)_cstr length:(unsigned)_l { + if (self->handle == NULL) return NULL; + return ap_pstrndup(self->handle, _cstr, _l); +} +- (unsigned char *)strcat:(const unsigned char *)_cstr { + if (self->handle == NULL) return NULL; + return ap_pstrcat(self->handle, _cstr, NULL); +} +- (unsigned char *)pvsprintf:(const unsigned char *)_fmt arguments:(va_list)va{ + if (self->handle == NULL) return NULL; + return ap_pvsprintf(self->handle, _fmt, va); +} + +/* file allocations */ + +- (FILE *)openFile:(NSString *)_name mode:(NSString *)_mode { + return ap_pfopen(self->handle, [_name cString], [_mode cString]); +} +- (FILE *)openFD:(int)_fd mode:(NSString *)_mode { + return ap_pfdopen(self->handle, _fd, [_mode cString]); +} +- (int)popenf:(NSString *)_name flag:(int)_flg mode:(int)_mode { + return ap_popenf(self->handle, [_name cString], _flg, _mode); +} + +- (void)closeFile:(FILE *)_file { + ap_pfclose(self->handle, _file); +} +- (void)pclosef:(int)_fd { + ap_pclosef(self->handle, _fd); +} +#ifdef WIN32 +- (void)closeHandle:(HANDLE)_h { + ap_pcloseh(self->handle, _h); +} +#endif + +- (void)noteCleanUpsForFile:(FILE *)_file { + ap_note_cleanups_for_file(self->handle, _file); +} +- (void)noteCleanUpsForFD:(int)_fd { + ap_note_cleanups_for_fd(self->handle, _fd); +} +#ifdef WIN32 +- (void)noteCleanUpsForHandle:(HANDLE)_h { + ap_note_cleanups_for_h(self->handle, _h); +} +#endif +- (void)killCleanUpsForFD:(int)_fd { + ap_kill_cleanups_for_fd(self->handle, _fd); +} + +/* process management */ + ++ (void)cleanUpForExec { + ap_cleanup_for_exec(); +} + ++ (void)blockAlarms { + ap_block_alarms(); +} ++ (void)unlockAlarms { + ap_unblock_alarms(); +} + +/* Objective-C objects */ + +static void plainReleaseCleanup(void *data) { + if (data) [(id)data release]; +} +static void childReleaseCleanup(void *data) { + if (data) { + if ([(id)data respondsToSelector:@selector(cleanupForApacheExec)]) + [(id)data cleanupForApacheExec]; + } +} + +- (void)releaseObject:(id)_object { + if (_object == nil) return; + + ap_block_alarms(); + ap_register_cleanup(self->handle, _object, + plainReleaseCleanup, + childReleaseCleanup); + ap_unblock_alarms(); +} +- (void)unreleaseObject:(id)_object { + if (_object == nil) return; + + ap_block_alarms(); + ap_kill_cleanup(self->handle, _object, plainReleaseCleanup); + ap_unblock_alarms(); +} + +@end /* ApacheResourcePool */ diff --git a/Recycler/mod_objc/ApacheServer.h b/Recycler/mod_objc/ApacheServer.h new file mode 100644 index 00000000..1d41070d --- /dev/null +++ b/Recycler/mod_objc/ApacheServer.h @@ -0,0 +1,57 @@ +// $Id: ApacheServer.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheServer_H__ +#define __ApacheServer_H__ + +#include + +@interface ApacheServer : ApacheObject +{ +} + +/* accessors */ + +- (ApacheServer *)nextServer; + +/* description of where the definition came from */ + +- (NSString *)definitionName; +- (unsigned int)definitionLineNumber; + +/* locations of server config info */ + +- (NSString *)srmConfigName; +- (NSString *)accessConfigName; + +- (NSString *)serverAdmin; +- (NSString *)serverHostName; +- (unsigned short)port; + +/* log files */ + +- (NSString *)errorFileName; +- (FILE *)errorLogFile; +- (int)logLevel; + +/* module-specific configuration for server, and defaults... */ + +- (BOOL)isVirtual; + +/* transaction handling */ + +- (NSTimeInterval)timeout; +- (NSTimeInterval)keepAliveTimeout; +- (int)keepAliveMax; +- (BOOL)keepAlive; +- (int)sendBufferSize; + +- (id)serverUserId; +- (id)serverGroupId; + +- (int)requestLineLimit; +- (int)requestFieldSizeLimit; +- (int)requestFieldCountLimit; + +@end + +#endif /* __ApacheServer_H__ */ diff --git a/Recycler/mod_objc/ApacheServer.m b/Recycler/mod_objc/ApacheServer.m new file mode 100644 index 00000000..3317ee7d --- /dev/null +++ b/Recycler/mod_objc/ApacheServer.m @@ -0,0 +1,151 @@ +// $Id: ApacheServer.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheServer.h" +#include +#import + +static NSString *mkString(const char *str) { + static Class NSStringClass = Nil; + unsigned len; + + if (str == NULL) return nil; + if (NSStringClass == Nil) NSStringClass = [NSString class]; + if ((len = strlen(str)) == 0) return nil; + + return [[[NSStringClass alloc] initWithCString:str] autorelease]; +} + +@implementation ApacheServer +#define AP_HANDLE ((server_rec *)self->handle) + +/* accessors */ + +- (ApacheServer *)nextServer { + return [[[ApacheServer alloc] initWithHandle:AP_HANDLE->next] autorelease]; +} + +/* description of where the definition came from */ + +- (NSString *)definitionName { + return mkString(AP_HANDLE->defn_name); +} +- (unsigned int)definitionLineNumber { + return AP_HANDLE->defn_line_number; +} + +/* Full locations of server config info */ + +- (NSString *)srmConfigName { + return mkString(AP_HANDLE->srm_confname); +} +- (NSString *)accessConfigName { + return mkString(AP_HANDLE->access_confname); +} + +- (NSString *)serverAdmin { + return mkString(AP_HANDLE->server_admin); +} +- (NSString *)serverHostName { + return mkString(AP_HANDLE->server_hostname); +} +- (unsigned short)port { + return AP_HANDLE->port; +} + +/* log files */ + +- (NSString *)errorFileName { + return mkString(AP_HANDLE->error_fname); +} +- (FILE *)errorLogFile { + return AP_HANDLE->error_log; +} +- (int)logLevel { + return AP_HANDLE->loglevel; +} + +/* module-specific configuration for server, and defaults... */ + +- (BOOL)isVirtual { + return AP_HANDLE->is_virtual ? YES : NO; +} + +/* transaction handling */ + +- (NSTimeInterval)timeout { + return AP_HANDLE->timeout; +} +- (NSTimeInterval)keepAliveTimeout { + return AP_HANDLE->keep_alive_timeout; +} +- (int)keepAliveMax { + return AP_HANDLE->keep_alive_max; +} +- (BOOL)keepAlive { + return AP_HANDLE->keep_alive ? YES : NO; +} +- (int)sendBufferSize { + return AP_HANDLE->send_buffer_size; +} + +- (NSString *)serverPath { + return [NSString stringWithCString:AP_HANDLE->path + length:AP_HANDLE->pathlen]; +} + +#warning names, wild_names + +- (id)serverUserId { + return [NSNumber numberWithInt:AP_HANDLE->server_uid]; +} +- (id)serverGroupId { + return [NSNumber numberWithInt:AP_HANDLE->server_gid]; +} + +- (int)requestLineLimit { + return AP_HANDLE->limit_req_line; +} +- (int)requestFieldSizeLimit { + return AP_HANDLE->limit_req_fieldsize; +} +- (int)requestFieldCountLimit { + return AP_HANDLE->limit_req_fields; +} + +/* description */ + +- (NSString *)description { + NSMutableString *ms; + id tmp; + + ms = [NSMutableString stringWithCapacity:128]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + [ms appendFormat:@" 0x%08X", self->handle]; + + if ([self isVirtual]) + [ms appendString:@" virtual"]; + + [ms appendFormat:@" uid=%@ gid=%@", + [self serverUserId], [self serverGroupId]]; + + if ([(tmp = [self definitionName]) length] > 0) + [ms appendFormat:@" def=%@:%i", tmp, [self definitionLineNumber]]; + + if ((tmp = [self serverHostName])) + [ms appendFormat:@" host=%@:%i", tmp, [self port]]; + +#if 0 + if ((tmp = [self serverAdmin])) + [ms appendFormat:@" admin=%@", tmp]; +#endif + + [ms appendFormat:@" loglevel=%i", [self logLevel]]; + + if ((tmp = [self nextServer])) + [ms appendFormat:@" next=%@", tmp]; + + [ms appendString:@">"]; + return ms; +} + +@end /* ApacheServer */ diff --git a/Recycler/mod_objc/ApacheTable.h b/Recycler/mod_objc/ApacheTable.h new file mode 100644 index 00000000..6a71d1e2 --- /dev/null +++ b/Recycler/mod_objc/ApacheTable.h @@ -0,0 +1,28 @@ +// $Id: ApacheTable.h,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#ifndef __ApacheTable_H__ +#define __ApacheTable_H__ + +#include "ApacheObject.h" + +@interface ApacheTable : ApacheObject +{ +} + +/* query */ + +- (id)objectForKey:(NSString *)_key; + +/* modification */ + +- (void)setObject:(id)_obj forKey:(NSString *)_key; + +- (void)mergeObject:(id)_obj forKey:(NSString *)_key; +- (void)addObject:(id)_obj forKey:(NSString *)_key; + +- (void)removeAllObjects; +- (void)removeObjectForKey:(NSString *)_key; + +@end + +#endif /* __ApacheTable_H__ */ diff --git a/Recycler/mod_objc/ApacheTable.m b/Recycler/mod_objc/ApacheTable.m new file mode 100644 index 00000000..f0f2a64b --- /dev/null +++ b/Recycler/mod_objc/ApacheTable.m @@ -0,0 +1,50 @@ +// $Id: ApacheTable.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "ApacheTable.h" +#import +#include +#include "httpd.h" +#include "ap_alloc.h" + +@implementation ApacheTable +#define AP_HANDLE ((table *)self->handle) + +/* query */ + +- (id)objectForKey:(NSString *)_key { + return [NSString stringWithCString:ap_table_get(AP_HANDLE, [_key cString])]; +} + +/* modification */ + +- (void)setObject:(id)_obj forKey:(NSString *)_key { + const char *v; + + if ((v = [[_obj stringValue] cString])) + ap_table_set(AP_HANDLE, [_key cString], v); + else + ap_table_unset(AP_HANDLE, [_key cString]); +} + +- (void)mergeObject:(id)_obj forKey:(NSString *)_key { + const char *v; + + if ((v = [[_obj stringValue] cString])) + ap_table_merge(AP_HANDLE, [_key cString], v); +} +- (void)addObject:(id)_obj forKey:(NSString *)_key { + const char *v; + + if ((v = [[_obj stringValue] cString])) + ap_table_add(AP_HANDLE, [_key cString], v); +} + +- (void)removeAllObjects { + ap_clear_table(AP_HANDLE); +} +- (void)removeObjectForKey:(NSString *)_key { + ap_table_unset(AP_HANDLE, [_key cString]); +} + +#undef AP_HANDLE +@end /* ApacheTable */ diff --git a/Recycler/mod_objc/GNUmakefile b/Recycler/mod_objc/GNUmakefile new file mode 100644 index 00000000..13732541 --- /dev/null +++ b/Recycler/mod_objc/GNUmakefile @@ -0,0 +1,50 @@ +# $Id: GNUmakefile,v 1.1 2004/06/08 11:15:59 helge Exp $ + +include $(GNUSTEP_MAKEFILES)/common.make + +LIBRARY_NAME = libApacheAPI libApHelper +BUNDLE_NAME = ApTest +MODULE_NAME = gsbundle + +libApacheAPI_OBJC_FILES = \ + ApacheCmdParms.m \ + ApacheConnection.m \ + ApacheObject.m \ + ApacheRequest.m \ + ApacheResourcePool.m \ + ApacheServer.m \ + ApacheTable.m \ + ApacheModule.m \ + ApModuleBaseClass.m \ + ApModuleBaseClass+Callbacks.m \ + ApModuleBaseClass+Handler.m \ + ApModuleBaseClass+Cmds.m \ + +libApHelper_OBJC_FILES = \ + GSBundleModule.m \ + +gsbundle_OBJC_FILES = \ + mod_gsbundle.m \ + +ApTest_PRINCIPAL_CLASS = ApTest +ApTest_OBJC_FILES = \ + ApTest.m \ + ApTest_module_structure.m \ + +libApHelper_LIBRARIES_DEPEND_UPON += \ + -lApacheAPI \ + -lFoundation \ + -lobjc \ + -lpthread + +ADDITIONAL_LIB_DIRS += -L./$(GNUSTEP_OBJ_DIR) +ApTest_BUNDLE_LIBS += -lApacheAPI + +gsbundle_TOOL_LIBS += -lpthread -ldl + +include $(GNUSTEP_MAKEFILES)/library.make +include $(GNUSTEP_MAKEFILES)/apache.make +include $(GNUSTEP_MAKEFILES)/bundle.make + +before-ApTest-all:: + genApacheModule.sh ApTest ApTest_module_structure.m diff --git a/Recycler/mod_objc/GSBundleModule.m b/Recycler/mod_objc/GSBundleModule.m new file mode 100644 index 00000000..bf803d5f --- /dev/null +++ b/Recycler/mod_objc/GSBundleModule.m @@ -0,0 +1,407 @@ +// $Id: GSBundleModule.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "httpd.h" +#include "http_config.h" +#include "http_log.h" +#include "ap_config.h" + +#include "ApacheCmdParms.h" +#include "ApacheServer.h" +#include "ApacheModule.h" +#include "ApacheResourcePool.h" +#import + +/* + Note: + + an Apache module gets *unloaded* during the config process !!! + + This is why we have this helper shared object which is not unloaded :-) +*/ + +@interface NSObject(ModuleClass) ++ (void)setBundleHandler:(id)_handler; +- (module *)apacheModule; +@end + +static void _ensureObjCEnvironment(void) { +#if LIB_FOUNDATION_LIBRARY + extern char **environ; /* man 5 environ */ + static char *argv[2] = { "apache", NULL }; + [NSProcessInfo initializeWithArguments:argv + count:1 + environment:environ]; +#endif +} + +@interface ApBundleInfo : NSObject +{ +@public + ApacheResourcePool *configPool; + NSString *bundlePath; + NSString *bundleName; + NSBundle *bundle; + module *apacheModule; + ApacheModule *bundleHandler; + BOOL moduleAdded; + BOOL bundleLoaded; +} + ++ (NSString *)makeBundlePathAbsolute:(NSString *)_relpath; ++ (ApBundleInfo *)bundleInfoForPath:(NSString *)_relpath; + +/* accessors */ + +- (NSBundle *)bundle; +- (NSString *)bundleModuleClassName; +- (Class)bundleModuleClass; + +- (BOOL)isBundleLoaded; +- (BOOL)isApacheModuleInitialized; + +/* operations */ + +- (NSString *)setUpWithArgs:(NSString *)_args + inPool:(ApacheResourcePool *)_pool; +- (void)tearDown; + +- (void)configureForServer:(ApacheServer *)_server; + +@end + +@implementation ApBundleInfo + ++ (ApBundleInfo *)bundleInfoForPath:(NSString *)_relpath { + static NSMutableDictionary *pathToInfo = nil; + NSString *p; + ApBundleInfo *bi; + + p = [self makeBundlePathAbsolute:_relpath]; + if ([p length] == 0) return nil; + + if (pathToInfo == nil) + pathToInfo = [[NSMutableDictionary alloc] initWithCapacity:16]; + + if ((bi = [pathToInfo objectForKey:p])) + return bi; + + if ((bi = [[self alloc] initWithPath:p])) { + [pathToInfo setObject:bi forKey:p]; + RELEASE(bi); + } + return bi; +} ++ (NSString *)makeBundlePathAbsolute:(NSString *)_relpath { + NSString *s; + + if ([_relpath length] == 0) return nil; + + s = [[[NSProcessInfo processInfo] + environment] + objectForKey:@"GNUSTEP_SYSTEM_ROOT"]; + s = [s stringByAppendingPathComponent:@"Library/Bundles"]; + s = [s stringByAppendingPathComponent:_relpath]; + + return s; +} + +- (id)initWithPath:(NSString *)_path { + if ([_path length] == 0) { + RELEASE(self); + return nil; + } + if (![_path isAbsolutePath]) { + NSLog(@"bundle path '%@' is not absolute ...", _path); + RELEASE(self); + return nil; + } + + self->bundlePath = [_path copy]; + self->bundleName = + [[[_path lastPathComponent] stringByDeletingPathExtension] copy]; + self->bundle = [[NSBundle bundleWithPath:self->bundlePath] retain]; + + if (self->bundle == nil) { + NSLog(@"missing bundle at path %@", self->bundlePath); + RELEASE(self); + return nil; + } + + return self; +} + +- (void)dealloc { + NSAutoreleasePool *pool; + + pool = [[NSAutoreleasePool alloc] init]; + RELEASE(self->configPool); + RELEASE(self->bundleHandler); + RELEASE(self->bundlePath); + RELEASE(self->bundleName); + RELEASE(self->bundle); + RELEASE(pool); + [super dealloc]; +} + +/* accessors */ + +- (BOOL)isBundleLoaded { + if (self->bundle == nil) return NO; + return self->bundleLoaded; +} +- (BOOL)isApacheModuleInitialized { + if (self->apacheModule == NULL) return NO; + return self->moduleAdded; +} + +- (NSBundle *)bundle { + return self->bundle; +} + +- (NSString *)bundleModuleClassName { + return [self->bundleName stringByAppendingString:@"Mod_Module_Class"]; +} +- (Class)bundleModuleClass { + /* the class which manages the module structure (helper class) */ + return NSClassFromString([self bundleModuleClassName]); +} + +- (Class)bundleHandlerClass { + /* the class which represents the apache module itself */ + Class c; + + if ((c = [self->bundle principalClass]) == Nil) + return nil; + if (![c isKindOfClass:[ApacheModule class]]) + return nil; + + return c; +} + +/* operations */ + +- (NSString *)setUpWithArgs:(NSString *)_args + inPool:(ApacheResourcePool *)_pool +{ + NSAutoreleasePool *pool; + Class modClass; + + /* check pre-conditions */ + + if (self->bundle == nil) { + return [NSString stringWithFormat:@"%s: missing bundle info", + __PRETTY_FUNCTION__]; + } + if (self->configPool) + return @"config pool is already setup"; + if (self->bundleHandler) + return @"bundle handler is already set up !!!"; + + pool = [[NSAutoreleasePool alloc] init]; + +#if 0 + printf("\nSETUP 0x%08X (loaded=%s) ...\n", (unsigned int)self, + self->bundleLoaded ? "yes" : "no"); + fflush(stdout); +#endif + + /* Step 0: setup resource pool wrapper */ + + self->configPool = RETAIN(_pool); + + /* Step 1: Load bundle if not done already ... */ + + if (!self->bundleLoaded) { + if (![self->bundle load]) { + return + [NSString stringWithFormat:@"couldn't load bundle %@", self->bundle]; + } + self->bundleLoaded = YES; + } + + if ((modClass = [self bundleModuleClass]) == Nil) { + RELEASE(pool); + return [NSString stringWithFormat: + @"did not find bundle module class (name=%@) ...", + [self bundleModuleClassName]]; + } + + /* Step 2: Initialize bundle handler object ... */ + + self->bundleHandler = [[[self bundleHandlerClass] alloc] init]; + if (self->bundleHandler == nil) { + RELEASE(pool); + return [NSString stringWithFormat: + @"couldn't initialize bundle handler of class '%@'", + [self bundleHandlerClass]]; + } + + /* Step 3: Remember bundle handler in module-handler class ... */ + + [modClass setBundleHandler:self->bundleHandler]; + + /* Step 4: add Apache C module structure */ + + if ((self->apacheModule = [modClass apacheModule]) == NULL) { + RELEASE(pool); + return @"did not find apache module structure of bundle"; + } + if (self->apacheModule->magic != MODULE_MAGIC_COOKIE) { + RELEASE(pool); + return [NSString stringWithFormat: + @"API module structure of bundle is broken !"]; + } + + /* Step 5: register module with apache ... */ + + ap_add_loaded_module(self->apacheModule); + self->moduleAdded = YES; + + /* release pool & done */ + + RELEASE(pool); + + return nil; +} + +- (void)tearDown { + NSAutoreleasePool *pool; + + pool = [[NSAutoreleasePool alloc] init]; + +#if 0 + printf("TEARDOWN 0x%08X ...\n", (unsigned int)self); + fflush(stdout); +#endif + + /* Reverse Step 5: unregister module with apache */ + + if ((self->apacheModule != NULL) && self->moduleAdded) + ap_remove_loaded_module(self->apacheModule); + + self->moduleAdded = NO; + + /* Reverse Step 4: reset apache module structure */ + self->apacheModule = NULL; + + /* Reverse Step 3: reset bundle handler in module-handler class ... */ + [[self bundleModuleClass] setBundleHandler:nil]; + + /* Reverse Step 2: release bundle handler object ... */ + RELEASE(self->bundleHandler); + self->bundleHandler = nil; + + /* DO NOT reverse Step 1 ... */ + + /* Reverse Step 0: release config pool proxy */ + RELEASE(self->configPool); self->configPool = nil; + + RELEASE(pool); +} + +- (void)configureForServer:(ApacheServer *)_server { + if (self->apacheModule == NULL) { + NSLog(@"missing bundle module ..."); + return; + } + if (self->configPool == NULL) { + NSLog(@"missing config pool ..."); + return; + } + +#if DEBUG && 0 + printf("CONFIGURE 0x%08X ...\n", (unsigned int)self); + fflush(stdout); +#endif + + ap_single_module_configure([self->configPool handle], + [_server handle], + self->apacheModule); +} + +@end /* ApBundleInfo */ + +static void unloadModule(void *data) { + ApBundleInfo *binfo; + + if ((binfo = (void *)data)) { + [binfo tearDown]; + } +} + +static int callCount = 0; + +/* Called when the LoadBundle config directive is found */ +const char *GSBundleModuleLoadBundleCommand +(module *module, cmd_parms *cmd, char *bundlePath) +{ + const char *result = NULL; + ApacheCmdParms *paras; + NSAutoreleasePool *opool; + NSString *bp, *args; + ApBundleInfo *bi; + id tmp; + + _ensureObjCEnvironment(); + callCount++; + +#if HEAVY_GSBUNDLE_DEBUG + printf("%s: #%i module=0x%08X pid=%i " + "(cmd=0x%08X,bp=0x%08X) ...\n", + __PRETTY_FUNCTION__, callCount, (unsigned int)module, getpid(), + (unsigned int)cmd, (unsigned int)bundlePath); + fflush(stdout); fflush(stderr); +#endif + + opool = [[NSAutoreleasePool alloc] init]; + paras = [[ApacheCmdParms alloc] initWithHandle:cmd]; + + /* separate bundle path from bundle args */ + + tmp = [NSString stringWithCString:bundlePath]; +#if HEAVY_GSBUNDLE_DEBUG + printf("%s: %s\n", __PRETTY_FUNCTION__, [[s description] cString]); + printf(" paras: %s\n", [[paras description] cString]); + printf(" server: %s\n", [[[paras server] description] cString]); + fflush(stdout); fflush(stderr); +#endif + + /* separate bundle path and load arguments ... */ + { + unsigned idx; + + if ((idx = [tmp indexOfString:@" "]) == NSNotFound) { + bp = tmp; + args = nil; + } + else { + bp = [tmp substringToIndex:idx]; + args = [tmp substringFromIndex:(idx + 1)]; + } + } + + /* makeup absolute bundle path */ + + if ((bi = [ApBundleInfo bundleInfoForPath:bp]) == nil) { + result = ap_pstrcat(cmd->pool, "bundle at '", [bp cString], "' could " + "not find info !"); + goto done; + } + + if ((tmp = [bi setUpWithArgs:args inPool:[paras pool]])) { + result = ap_pstrdup(cmd->pool, [tmp cString]); + goto done; + } + + /* register cleanup */ + ap_register_cleanup(cmd->pool, bi, + (void (*)(void*))unloadModule, ap_null_cleanup); + + /* run module configuration */ + [bi configureForServer:[paras server]]; + + done: + RELEASE(paras); + RELEASE(opool); + return result; +} diff --git a/Recycler/mod_objc/README b/Recycler/mod_objc/README new file mode 100644 index 00000000..21bd560b --- /dev/null +++ b/Recycler/mod_objc/README @@ -0,0 +1,7 @@ +# $Id: README,v 1.1 2004/06/08 11:15:59 helge Exp $ + +TODO +- resolve mem-leaks created by handler and command tables + +Last change: 20011126? + diff --git a/Recycler/mod_objc/genApacheModule.sh b/Recycler/mod_objc/genApacheModule.sh new file mode 100755 index 00000000..e338b49c --- /dev/null +++ b/Recycler/mod_objc/genApacheModule.sh @@ -0,0 +1,146 @@ +#!/bin/sh + +MODULENAME=$1 +MFILE=$2 +MODULECLASS="${MODULENAME}Mod_Module_Class" + +# +# This tool is used to generate Apache module stub structures and classes. +# +# An Objective-C class is used to "emulate" a module object. +# + +echo "creating structure for Apache module ${MODULENAME} in file ${MFILE} ..." + +cat >$MFILE < +#include "http_config.h" +#import +#import +#include "ApacheModule.h" + +static module ${MODULENAME}_module_template; +module MODULE_VAR_EXPORT ${MODULENAME}_module; + +@interface ${MODULECLASS} : ApModuleBaseClass +@end + +@implementation ${MODULECLASS} + +static ApacheModule *bundleHandler = nil; + ++ (void)setBundleHandler:(ApacheModule *)_handler { + if (_handler == bundleHandler) + return; + + if ((bundleHandler != nil) && (_handler != nil)) { + printf("WARNING(%s): handler of bundle %s already set !\n", + __PRETTY_FUNCTION__, + [[[NSBundle bundleForClass:self] description] cString]); + } + + ASSIGN(bundleHandler, _handler); +} ++ (ApacheModule *)bundleHandler { + return bundleHandler; +} + ++ (void *)apacheTemplateModule { + return &(${MODULENAME}_module_template); +} ++ (void *)apacheModuleStructure { + return &${MODULENAME}_module; +} + +static int _handleRequest(request_rec *_request) { + return [${MODULECLASS} _handleRequest:_request]; +} ++ (void *)handleRequestStubFunction { + return &_handleRequest; +} + +@end /* ${MODULECLASS} */ + +static void _moduleInit(server_rec *s, pool *p) { + [${MODULECLASS} _moduleInit:s pool:p]; +} + +static void *_perDirConfCreate(pool *p, char *dirspec) { + return [${MODULECLASS} _perDirConfCreate:dirspec pool:p]; +} +static void *_perDirConfMerge(pool *p, void *baseConf, void *newConf) { + return [${MODULECLASS} _perDirConfMerge:baseConf with:newConf pool:p]; +} + +static void *_perServerConfCreate(pool *p, server_rec *s) { + return [${MODULECLASS} _perServerConfCreate:s pool:p]; +} +static void *_perServerConfMerge(pool *p, void *baseConf, void *newConf) { + return [${MODULECLASS} _perServerConfMerge:baseConf with:newConf pool:p]; +} + +static int _translateHandler(request_rec *_request) { + return [${MODULECLASS} _translateHandler:_request]; +} +static int _apCheckUserId(request_rec *_request) { + return [${MODULECLASS} _apCheckUserId:_request]; +} +static int _authChecker(request_rec *_request) { + return [${MODULECLASS} _authChecker:_request]; +} +static int _accessChecker(request_rec *_request) { + return [${MODULECLASS} _accessChecker:_request]; +} +static int _typeChecker(request_rec *_request) { + return [${MODULECLASS} _typeChecker:_request]; +} +static int _fixerUpper(request_rec *_request) { + return [${MODULECLASS} _fixerUpper:_request]; +} +static int _logger(request_rec *_request) { + return [${MODULECLASS} _logger:_request]; +} +static int _headerParser(request_rec *_request) { + return [${MODULECLASS} _headerParser:_request]; +} + +static void _childInit(server_rec *_server, pool *_pool) { + [${MODULECLASS} _childInit:_server pool:_pool]; +} +static void _childExit(server_rec *_server, pool *_pool) { + [${MODULECLASS} _childExit:_server pool:_pool]; +} + +static int _postReadRequest(request_rec *_request) { + return [${MODULECLASS} _postReadRequest:_request]; +} + +static module ${MODULENAME}_module_template = { + STANDARD_MODULE_STUFF, + _moduleInit, _perDirConfCreate, _perDirConfMerge, + _perServerConfCreate, _perServerConfMerge, + NULL, /* table of config file commands */ + NULL, /* [#8] MIME-typed-dispatched handlers */ + _translateHandler, _apCheckUserId, _authChecker, _accessChecker, + _typeChecker, _fixerUpper, _logger, _headerParser, + _childInit, _childExit, _postReadRequest +}; + +module MODULE_VAR_EXPORT ${MODULENAME}_module = { + STANDARD_MODULE_STUFF, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +EOF diff --git a/Recycler/mod_objc/mod_gsbundle.m b/Recycler/mod_objc/mod_gsbundle.m new file mode 100644 index 00000000..cafda6a6 --- /dev/null +++ b/Recycler/mod_objc/mod_gsbundle.m @@ -0,0 +1,91 @@ +// $Id: mod_gsbundle.m,v 1.1 2004/06/08 11:15:59 helge Exp $ + +#include "httpd.h" +#include "http_config.h" +#include + +/* + Note: + + an Apache bundle gets *unloaded* during the config process !!! +*/ + +module MODULE_VAR_EXPORT gsbundle_module; + +static void *helperLib = NULL; + +static const char *(*GSBundleModuleLoadBundleCommand) +(module *module, cmd_parms *cmd, char *bundlePath) = NULL; + +/* Called when the LoadBundle config directive is found */ +static const char *loadBundle +(cmd_parms *cmd, void *dummy, char *bundlePath) +{ + if (helperLib == NULL) { + const char *path; + const char *dirpath; + + dirpath = ap_pstrcat(cmd->pool, + getenv("GNUSTEP_SYSTEM_ROOT"), "/Libraries/", + getenv("GNUSTEP_HOST_CPU"), "/", + getenv("GNUSTEP_HOST_OS"), "/", + getenv("LIBRARY_COMBO"), "/", + NULL); + path = ap_pstrcat(cmd->pool, dirpath, "libApHelper_d.so", NULL); + + helperLib = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (helperLib == NULL) { + return ap_pstrcat(cmd->pool, + "couldn't load ObjC bundle helper lib:\n '", + path, + "' ..." , NULL); + } + + GSBundleModuleLoadBundleCommand = + dlsym(helperLib, "GSBundleModuleLoadBundleCommand"); + } + + if (GSBundleModuleLoadBundleCommand == NULL){ + return ap_pstrcat(cmd->pool, + "couldn't find load bundle command in helper lib ...", + NULL); + } + + return GSBundleModuleLoadBundleCommand(&gsbundle_module, cmd, bundlePath); +} + +/* Config file commands we recognize */ +static const command_rec gsbundle_cmds[] = +{ + { + "LoadBundle", + loadBundle, + "my userinfo", + RSRC_CONF, + RAW_ARGS, + "takes bundle-path as arg" + }, + {NULL} +}; + +module MODULE_VAR_EXPORT gsbundle_module = { + STANDARD_MODULE_STUFF, + NULL, /* module initializer */ + NULL, /* create per-dir config structures */ + NULL, /* merge per-dir config structures */ + NULL, /* create per-server config structures */ + NULL, /* merge per-server config structures */ + gsbundle_cmds, /* table of config file commands */ + NULL, /* [#8] MIME-typed-dispatched handlers */ + NULL, /* [#1] URI to filename translation */ + NULL, /* [#4] validate user id from request */ + NULL, /* [#5] check if the user is ok _here_ */ + NULL, /* [#3] check access by host address */ + NULL, /* [#6] determine MIME type */ + NULL, /* [#7] pre-run fixups */ + NULL, /* [#9] log a transaction */ + NULL, /* [#2] header parser */ + NULL, /* child_init */ + NULL, /* child_exit */ + NULL /* [#0] post read-request */ +}; diff --git a/Recycler/mod_objc/test.conf b/Recycler/mod_objc/test.conf new file mode 100644 index 00000000..58b513f8 --- /dev/null +++ b/Recycler/mod_objc/test.conf @@ -0,0 +1,121 @@ +# $Id: test.conf,v 1.1 2004/06/08 11:15:59 helge Exp $ + +# globals +ServerType standalone +ServerRoot "/HOME/helge/mdev/SkyrixRoot" +PidFile /HOME/helge/mdev/SkyrixRoot/logs/httpd.pid +ScoreBoardFile /HOME/helge/mdev/SkyrixRoot/logs/httpd.scoreboard +DocumentRoot "/HOME/helge/mdev/SkyrixRoot/Library/WebServer/Documents" +ErrorLog /HOME/helge/mdev/SkyrixRoot/logs/error_log +AccessFileName .htaccess +Timeout 300 +KeepAlive On +MaxKeepAliveRequests 100 +KeepAliveTimeout 15 +MinSpareServers 1 +MaxSpareServers 1 +StartServers 1 +MaxClients 150 +MaxRequestsPerChild 0 +ExtendedStatus On +Port 8090 +User helge +Group dev +ServerAdmin helge.hess@skyrix.com +HostnameLookups Off +ServerSignature On + +#LoadModule dav_module Libraries/ix86/linux-gnu/apache/libdav.so +#AddModule mod_dav.c + +LoadModule gnustep_conf_module \ + Libraries/ix86/linux-gnu/apache/mod_gnustep_conf.so + +# GNUstep Config + +#GNUstepRootPath /HOME/helge/mdev/SkyrixRoot + +# load bundle loader ... + +LoadModule gsbundle_module \ + Libraries/ix86/linux-gnu/apache/mod_gsbundle.so +AddModule mod_gsbundle.m + +# load a bundle ... + +LoadBundle ApTest.bundle +#a=10 b=20 + + + Options FollowSymLinks + AllowOverride None + MyDirAlias diraliasaa documents + MyDirAlias diralias2aa documents2 + PrintDirConfig 1 + + +MyServerAlias server alias + + + Options Indexes FollowSymLinks MultiViews + AllowOverride None + Order allow,deny + Allow from all + #SetHandler ap-test + MyDirAlias diralias documents + MyDirAlias diralias2 documents2 + PrintDirConfig 1 + + + + DirectoryIndex index.xhtml index.html + + + + Order allow,deny + Deny from all + + +UseCanonicalName On + + + TypesConfig /HOME/helge/mdev/SkyrixRoot/Library/WebServer/mime.types + + +DefaultType text/plain + +# LogLevel: Control the number of messages logged to the error_log. +# Possible values include: debug, info, notice, warn, error, crit, +# alert, emerg. +# +LogLevel warn + +LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined +LogFormat "%h %l %u %t \"%r\" %>s %b" common +LogFormat "%{Referer}i -> %U" referer +LogFormat "%{User-agent}i" agent + +CustomLog /HOME/helge/mdev/SkyrixRoot/logs/access_log common + +# Alias fakename realname + + + + + AddEncoding x-compress Z + AddEncoding x-gzip gz tgz + AddLanguage en .en + AddLanguage fr .fr + AddLanguage de .de + AddCharset UCS-2 .ucs2 + AddCharset UCS-4 .ucs4 + AddCharset UTF-8 .utf8 + + + + BrowserMatch "Mozilla/2" nokeepalive + BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 + BrowserMatch "RealPlayer 4\.0" force-response-1.0 + BrowserMatch "Java/1\.0" force-response-1.0 + BrowserMatch "JDK/1\.0" force-response-1.0 +