mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-04-23 15:33:43 +00:00
* rewrote large parts of GSWDefaultAdaptor
* new GSWHTTPIO and GSWWorkerThread * dropped GSWDefaultAdaptorThread * some takeValue:forKey: fixes * started to remove global inclues git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@25611 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
250ed2c524
commit
e8b2f11ba2
25 changed files with 1113 additions and 1737 deletions
|
@ -1,6 +1,12 @@
|
|||
2007-11-25 David Wetzel <dave@turbocat.de>
|
||||
* GSWAdaptors/Apache2/mod_gsw.c
|
||||
Works also if a header or empty line at the end of the headers has a \r\n ending.
|
||||
GSWeb.framework:
|
||||
* rewrote large parts of GSWDefaultAdaptor
|
||||
* new GSWHTTPIO and GSWWorkerThread
|
||||
* dropped GSWDefaultAdaptorThread
|
||||
* some takeValue:forKey: fixes
|
||||
* started to remove global inclues
|
||||
|
||||
2007-11-24 David Ayers <ayers@fsfe.org>
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ GSWConstants.m \
|
|||
GSWTemporaryElement.m \
|
||||
GSWBaseParser.m \
|
||||
GSWHTMLRawParser.m \
|
||||
GSWHTTPIO.m \
|
||||
GSWDeclaration.m \
|
||||
GSWDeclarationParser.m \
|
||||
GSWTemplateParser.m \
|
||||
|
@ -164,7 +165,6 @@ GSWComponentRequestHandler.m \
|
|||
GSWResourceRequestHandler.m \
|
||||
GSWActionRequestHandler.m \
|
||||
GSWDirectActionRequestHandler.m \
|
||||
GSWDefaultAdaptorThread.m \
|
||||
GSWKeyValueAssociation.m \
|
||||
GSWHTMLStaticElement.m \
|
||||
GSWHTMLStaticGroup.m \
|
||||
|
@ -191,6 +191,7 @@ GSWStaticResourceRequestHandler.m \
|
|||
GSWRecording.m \
|
||||
GSWInputStreamData.m \
|
||||
GSWActionURL.m \
|
||||
GSWWorkerThread.m \
|
||||
|
||||
#For next Version:
|
||||
#GSWAdminAction.m \
|
||||
|
@ -229,7 +230,6 @@ GSWConstantValueAssociation.h \
|
|||
GSWContext.h \
|
||||
GSWCookie.h \
|
||||
GSWDefaultAdaptor.h \
|
||||
GSWDefaultAdaptorThread.h \
|
||||
GSWDeployedBundle.h \
|
||||
GSWAction.h \
|
||||
GSWDirectAction.h \
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#ifndef _GSWAdaptor_h__
|
||||
#define _GSWAdaptor_h__
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
|
||||
|
||||
//====================================================================
|
||||
// GSWAdaptor
|
||||
|
@ -35,13 +37,13 @@
|
|||
arguments:(NSDictionary*)arguments;
|
||||
-(void)registerForEvents;
|
||||
-(void)unregisterForEvents;
|
||||
-(void)runOnce;
|
||||
-(BOOL)doesBusyRunOnce;
|
||||
-(BOOL)dispatchesRequestsConcurrently;
|
||||
-(int)port;
|
||||
-(id)workerThreadCount;
|
||||
-(void)adaptorThreadExited:(GSWDefaultAdaptorThread*)adaptorThread;
|
||||
-(BOOL)isMultiThreadEnabled;
|
||||
|
||||
// deprecated since?
|
||||
-(void)runOnce;
|
||||
-(BOOL)doesBusyRunOnce;
|
||||
|
||||
@end
|
||||
|
||||
//====================================================================
|
||||
|
@ -50,4 +52,9 @@
|
|||
forApplicationNamed:(NSString*)applicationName;
|
||||
@end
|
||||
|
||||
// FIXME: check if that exists:
|
||||
// -(id)workerThreadCount;
|
||||
//-(void)adaptorThreadExited:(GSWDefaultAdaptorThread*)adaptorThread;
|
||||
//-(BOOL)isMultiThreadEnabled;
|
||||
|
||||
#endif //_GSWAdaptor_h__
|
||||
|
|
|
@ -43,11 +43,9 @@ RCS_ID("$Id$")
|
|||
-(id)initWithName:(NSString*)name
|
||||
arguments:(NSDictionary*)arguments
|
||||
{
|
||||
NSDebugMLog(@"Init");
|
||||
self=[super init];
|
||||
LOGObjectFnStop();
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
@ -67,54 +65,31 @@ RCS_ID("$Id$")
|
|||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// runOnce
|
||||
// depricated at least in 5.something
|
||||
-(void)runOnce
|
||||
{
|
||||
//TODOFN
|
||||
};
|
||||
//Does Nothing
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// doesBusyRunOnce
|
||||
// depricated at least in 5.something
|
||||
-(BOOL)doesBusyRunOnce
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
return NO;
|
||||
};
|
||||
return YES;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(BOOL)dispatchesRequestsConcurrently
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
return NO;
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// port
|
||||
-(int)port
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
return 0;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(id)workerThreadCount
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return nil;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)adaptorThreadExited:(GSWDefaultAdaptorThread*)adaptorThread
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(BOOL)isMultiThreadEnabled
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
return NO;
|
||||
};
|
||||
return -1;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
@ -126,5 +101,5 @@ RCS_ID("$Id$")
|
|||
forApplicationNamed:(NSString*)applicationName
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
};
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -55,6 +55,23 @@ GSWEB_EXPORT int GSWebNamingConv;//GSWNAMES_INDEX or WONAMES_INDEX
|
|||
(GSWebNamingConv==GSWNAMES_INDEX ? WONAMES_INDEX : GSWNAMES_INDEX))
|
||||
|
||||
GSWEB_EXPORT BOOL WOStrictFlag;
|
||||
|
||||
@class GSWSessionStore;
|
||||
@class GSWStatisticsStore;
|
||||
@class GSWResourceManager;
|
||||
@class GSWRequestHandler;
|
||||
@class GSWLifebeatThread;
|
||||
@class GSWSession;
|
||||
@class GSWAdaptor;
|
||||
@class GSWComponent;
|
||||
@class GSWElement;
|
||||
@class GSWResponse;
|
||||
@class GSWAssociation;
|
||||
@class GSWComponentDefinition;
|
||||
@class GSWMultiKeyDictionary;
|
||||
@class GSWActionRequestHandler;
|
||||
@class GSWAction;
|
||||
|
||||
//====================================================================
|
||||
@interface GSWApplication : NSObject <NSLocking>
|
||||
{
|
||||
|
|
|
@ -1369,6 +1369,7 @@ int GSWApplicationMain(NSString* applicationClassName,
|
|||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// dw: I do not know if this exists in WO
|
||||
-(Class)requestClass
|
||||
{
|
||||
NSString* requestClassName=[self requestClassName];
|
||||
|
@ -1378,6 +1379,8 @@ int GSWApplicationMain(NSString* applicationClassName,
|
|||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// dw: I do not know if this exists in WO
|
||||
|
||||
-(GSWRequest*)createRequestWithMethod:(NSString*)aMethod
|
||||
uri:(NSString*)anURL
|
||||
httpVersion:(NSString*)aVersion
|
||||
|
@ -2507,8 +2510,6 @@ to another instance **/
|
|||
sessionID=[requestHandlerValues objectForKey:GSWKey_SessionID[GSWebNamingConv]];
|
||||
if (!sessionID)
|
||||
{
|
||||
NSLog(@"Application : sessionID is nil");
|
||||
|
||||
if ([self isRefusingNewSessions])
|
||||
{
|
||||
NSLog(@"refuseRequest !");
|
||||
|
|
|
@ -849,7 +849,7 @@ static Class NSStringClass = Nil;
|
|||
{
|
||||
// no exception, set the value
|
||||
|
||||
[tmpObject takeValue:value
|
||||
[tmpObject setValue:value
|
||||
forKey:tmpKey];
|
||||
}
|
||||
}
|
||||
|
@ -940,7 +940,7 @@ static Class NSStringClass = Nil;
|
|||
else
|
||||
{
|
||||
GSWLogAssertGood(tmpObject);
|
||||
[tmpObject takeValue:value
|
||||
[tmpObject setValue:value
|
||||
forKey:part];
|
||||
#ifdef HAVE_GDL2
|
||||
// Turbocat
|
||||
|
|
|
@ -451,7 +451,7 @@ static Class GSWHTMLBareStringClass = Nil;
|
|||
[self smartTakeValue: obj
|
||||
forKey: myKey];
|
||||
#else
|
||||
[self takeValue: obj
|
||||
[self setValue: obj
|
||||
forKey: myKey];
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -27,9 +27,19 @@
|
|||
#ifndef _GSWDefaultAdaptor_h__
|
||||
#define _GSWDefaultAdaptor_h__
|
||||
|
||||
#include "GSWDefines.h"
|
||||
#include "GSWWOCompatibility.h"
|
||||
#include "GSWAdaptor.h"
|
||||
|
||||
@class GSWWorkerThread;
|
||||
@class NSDictionary;
|
||||
@class NSString;
|
||||
@class NSFileHandle;
|
||||
@class NSMutableArray;
|
||||
@class NSLock;
|
||||
|
||||
GSWEB_EXPORT int iBlock;
|
||||
//====================================================================
|
||||
// GSWDefaultAdaptor
|
||||
|
||||
|
||||
@interface GSWDefaultAdaptor: GSWAdaptor
|
||||
{
|
||||
|
@ -41,12 +51,20 @@ GSWEB_EXPORT int iBlock;
|
|||
int _workerThreadCount;
|
||||
int _workerThreadCountMin;
|
||||
int _workerThreadCountMax;
|
||||
int _listenQueueSize;
|
||||
int _maxSocketIdleTime;
|
||||
int _maxWorkerThreads;
|
||||
int __nmbOfWorkerThreads;
|
||||
int __nmbOfActiveThreads;
|
||||
int __windowSize;
|
||||
|
||||
BOOL _isMultiThreadEnabled;
|
||||
NSFileHandle* _fileHandle;
|
||||
NSMutableArray* _waitingThreads;
|
||||
NSMutableArray* _threads;
|
||||
NSLock* _selfLock;
|
||||
BOOL _blocked;
|
||||
BOOL _shouldGrow;
|
||||
}
|
||||
|
||||
-(id)initWithName:(NSString*)name
|
||||
|
@ -60,8 +78,6 @@ GSWEB_EXPORT int iBlock;
|
|||
-(BOOL)dispatchesRequestsConcurrently;
|
||||
-(int)port;
|
||||
-(NSString*)host;
|
||||
-(void)adaptorThreadExited:(GSWDefaultAdaptorThread*)adaptorThread;
|
||||
-(BOOL)tryLock;
|
||||
-(void)unlock;
|
||||
|
||||
-(void)setWorkerThreadCount:(id)workerThreadCount;
|
||||
|
@ -75,6 +91,8 @@ GSWEB_EXPORT int iBlock;
|
|||
-(BOOL)isConnectionAllowedWithHandle:(NSFileHandle*)handle
|
||||
returnedMessage:(NSString**)retMessage;
|
||||
|
||||
- (void) workerThreadWillExit:(GSWWorkerThread*) thread;
|
||||
|
||||
@end
|
||||
|
||||
//====================================================================
|
||||
|
|
|
@ -30,17 +30,26 @@
|
|||
</license>
|
||||
**/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
RCS_ID("$Id$")
|
||||
#include "config.h"
|
||||
#include "GSWDefaultAdaptor.h"
|
||||
|
||||
#include <Foundation/NSFileHandle.h>
|
||||
#include <Foundation/NSLock.h>
|
||||
|
||||
#include "GSWeb.h"
|
||||
|
||||
#include "GSWWorkerThread.h"
|
||||
|
||||
#if HAVE_LIBWRAP
|
||||
#include <tcpd.h>
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
|
||||
RCS_ID("$Id$")
|
||||
|
||||
|
||||
#if HAVE_LIBWRAP
|
||||
int deny_severity = LOG_WARNING;
|
||||
int allow_severity = LOG_INFO;
|
||||
|
@ -50,15 +59,30 @@ int allow_severity = LOG_INFO;
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
static GSWResponse * static_lastDitchErrorResponse = nil;
|
||||
|
||||
//====================================================================
|
||||
@implementation GSWDefaultAdaptor
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSWDefaultAdaptor class]) {
|
||||
if (static_lastDitchErrorResponse == nil) {
|
||||
static_lastDitchErrorResponse = [GSWResponse new];
|
||||
[static_lastDitchErrorResponse setStatus:500];
|
||||
[static_lastDitchErrorResponse appendContentString:@"An Internal Server Error Has Occurred."];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+(GSWResponse*) _lastDitchErrorResponse
|
||||
{
|
||||
return static_lastDitchErrorResponse;
|
||||
}
|
||||
|
||||
-(id)initWithName:(NSString*)name
|
||||
arguments:(NSDictionary*)arguments
|
||||
{
|
||||
NSDebugMLog(@"Init");
|
||||
if ((self=[super initWithName:name
|
||||
arguments:arguments]))
|
||||
{
|
||||
|
@ -75,92 +99,129 @@ int allow_severity = LOG_INFO;
|
|||
_workerThreadCountMax=[[arguments objectForKey:GSWOPT_WorkerThreadCountMax[GSWebNamingConv]] intValue];
|
||||
_isMultiThreadEnabled=[[arguments objectForKey:GSWOPT_MultiThreadEnabled] boolValue];
|
||||
ASSIGN(_adaptorHost,[arguments objectForKey:GSWOPT_AdaptorHost[GSWebNamingConv]]);
|
||||
};
|
||||
LOGObjectFnStop();
|
||||
|
||||
if ((_workerThreadCountMax <1) || (_isMultiThreadEnabled == NO)) {
|
||||
_workerThreadCountMax = 1;
|
||||
_isMultiThreadEnabled = NO;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)dealloc
|
||||
{
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor");
|
||||
//TODO? DESTROY(listenPortObject);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor: host");
|
||||
DESTROY(_host);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor: adaptorHost");
|
||||
DESTROY(_adaptorHost);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor: fileHandle");
|
||||
DESTROY(_fileHandle);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor: threads");
|
||||
DESTROY(_threads);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor: waitingThreads");
|
||||
DESTROY(_waitingThreads);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor: selfLock");
|
||||
DESTROY(_selfLock);
|
||||
GSWLogMemC("Dealloc GSWDefaultAdaptor Super");
|
||||
|
||||
[super dealloc];
|
||||
GSWLogMemC("End Dealloc GSWDefaultAdaptor");
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)registerForEvents
|
||||
{
|
||||
NSDebugDeepMLog(@"START registerForEvents - %@",
|
||||
GSCurrentThread());
|
||||
NSAssert(!_fileHandle,@"fileHandle already exists");
|
||||
NSDebugDeepMLLog(@"info",@"registerForEvents port=%d",_port);
|
||||
NSDebugDeepMLLog(@"info",@"registerForEvents host=%@",_host);
|
||||
if (!_host)
|
||||
{
|
||||
ASSIGN(_host,[[NSHost currentHost] name]);
|
||||
};
|
||||
_fileHandle=[[NSFileHandle fileHandleAsServerAtAddress:_host
|
||||
service:GSWIntToNSString(_port)
|
||||
protocol:@"tcp"] retain];
|
||||
NSDebugDeepMLLog(@"info",@"fileHandle=%p",(void*)_fileHandle);
|
||||
NSAssert(_fileHandle,@"No fileHandle to wait for connections");
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector: @selector(announceNewConnection:)
|
||||
name: NSFileHandleConnectionAcceptedNotification
|
||||
object:_fileHandle];
|
||||
/* [NotificationDispatcher addObserver:self
|
||||
selector: @selector(announceNewConnection:)
|
||||
name: NSFileHandleConnectionAcceptedNotification
|
||||
object:fileHandle];
|
||||
*/
|
||||
[_fileHandle acceptConnectionInBackgroundAndNotify];
|
||||
#ifndef __APPLE__
|
||||
NSAssert([_fileHandle readInProgress],@"No [_fileHandle readInProgress]");
|
||||
NSDebugDeepMLog(@"%@ - B readInProgress=%d",
|
||||
GSCurrentThread(),(int)[_fileHandle readInProgress]);
|
||||
#endif
|
||||
[GSWApplication statusLogWithFormat:
|
||||
@"Thread %@: Waiting for connections on %@:%d.",
|
||||
GSCurrentThread(),
|
||||
_host,
|
||||
_port];
|
||||
NSDebugDeepMLog(@"STOP registerForEvents");
|
||||
};
|
||||
SYNCHRONIZED(_selfLock) {
|
||||
NSAssert(!_fileHandle,@"fileHandle already exists");
|
||||
if (!_host) {
|
||||
ASSIGN(_host, @"localhost");
|
||||
}
|
||||
_fileHandle=[[NSFileHandle fileHandleAsServerAtAddress:_host
|
||||
service:GSWIntToNSString(_port)
|
||||
protocol:@"tcp"] retain];
|
||||
|
||||
NSAssert(_fileHandle,@"No fileHandle to wait for connections");
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(announceNewConnection:)
|
||||
name:NSFileHandleConnectionAcceptedNotification
|
||||
object:_fileHandle];
|
||||
|
||||
[_fileHandle acceptConnectionInBackgroundAndNotify];
|
||||
|
||||
#ifndef __APPLE__
|
||||
NSAssert([_fileHandle readInProgress],@"No [_fileHandle readInProgress]");
|
||||
NSDebugDeepMLog(@"%@ - B readInProgress=%d", GSCurrentThread(),(int)[_fileHandle readInProgress]);
|
||||
#endif
|
||||
[GSWApplication statusLogWithFormat:
|
||||
@"Thread %@: Waiting for connections on %@:%d.",
|
||||
GSCurrentThread(),
|
||||
_host,
|
||||
_port];
|
||||
}
|
||||
END_SYNCHRONIZED;
|
||||
}
|
||||
|
||||
//PRIVATE use only if locked!
|
||||
void _workOnHandle(NSFileHandle* handle, id adaptor, NSMutableArray* threadArray, BOOL isMultiThreadEnabled)
|
||||
{
|
||||
GSWWorkerThread * thread = [GSWWorkerThread alloc];
|
||||
|
||||
thread = [thread initWithApp:GSWApp
|
||||
adaptor:adaptor
|
||||
stream:handle];
|
||||
if (isMultiThreadEnabled) {
|
||||
[threadArray addObject: thread];
|
||||
}
|
||||
[thread release];
|
||||
|
||||
}
|
||||
|
||||
//PRIVATE use only if locked!
|
||||
void _queueWorkOnHandle(NSFileHandle* handle, NSMutableArray* waitingThreadArray) {
|
||||
[waitingThreadArray insertObject: handle
|
||||
atIndex: [waitingThreadArray count]];
|
||||
}
|
||||
|
||||
// never called if single threaded.
|
||||
- (void) workerThreadWillExit:(GSWWorkerThread*) thread
|
||||
{
|
||||
[_selfLock lock];
|
||||
[_threads removeObject: thread];
|
||||
if ([_waitingThreads count]) {
|
||||
_workOnHandle([_waitingThreads objectAtIndex:0], self, _threads, _isMultiThreadEnabled);
|
||||
[_waitingThreads removeObjectAtIndex:0];
|
||||
}
|
||||
[_selfLock unlock];
|
||||
}
|
||||
|
||||
//PRIVATE!
|
||||
// we are locked when we do this.
|
||||
-(void) _lockedShutdownThreads
|
||||
{
|
||||
NS_DURING {
|
||||
// loop throuh all threads and quit all not working ones until all shutdown
|
||||
}
|
||||
NS_HANDLER {
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)unregisterForEvents
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSFileHandleConnectionAcceptedNotification
|
||||
object:_fileHandle];
|
||||
/* [NotificationDispatcher removeObserver:self
|
||||
name: NSFileHandleConnectionAcceptedNotification
|
||||
object:fileHandle];
|
||||
*/
|
||||
DESTROY(_fileHandle);
|
||||
};
|
||||
SYNCHRONIZED(_selfLock) {
|
||||
NSAssert(_fileHandle,@"not registered");
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSFileHandleConnectionAcceptedNotification
|
||||
object:_fileHandle];
|
||||
_shouldGrow = NO;
|
||||
|
||||
[self _lockedShutdownThreads];
|
||||
|
||||
DESTROY(_fileHandle);
|
||||
|
||||
}
|
||||
END_SYNCHRONIZED;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)runOnce
|
||||
{
|
||||
//call doesBusyRunOnce
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(BOOL)doesBusyRunOnce
|
||||
|
@ -193,596 +254,61 @@ int allow_severity = LOG_INFO;
|
|||
-(id)workerThreadCount
|
||||
{
|
||||
return GSWIntNumber(_workerThreadCount);
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)setWorkerThreadCount:(id)workerThreadCount
|
||||
{
|
||||
if ([self tryLock])
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
_workerThreadCount=[workerThreadCount intValue];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO
|
||||
};
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)setWorkerThreadCountMin:(id)workerThreadCount
|
||||
-(void)announceNewConnection:(NSNotification*)notification
|
||||
{
|
||||
if ([self tryLock])
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
_workerThreadCountMin=[workerThreadCount intValue];
|
||||
if (_workerThreadCountMin<1)
|
||||
_workerThreadCountMin=1;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO
|
||||
};
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(id)workerThreadCountMin
|
||||
{
|
||||
return GSWIntNumber(_workerThreadCountMin);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)setWorkerThreadCountMax:(id)workerThreadCount
|
||||
{
|
||||
if ([self tryLock])
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
_workerThreadCountMax=[workerThreadCount intValue];
|
||||
if (_workerThreadCountMax<1)
|
||||
_workerThreadCountMax=1;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO
|
||||
};
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(id)workerThreadCountMax
|
||||
{
|
||||
return GSWIntNumber(_workerThreadCountMax);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(BOOL)isMultiThreadEnabled
|
||||
{
|
||||
return _isMultiThreadEnabled;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)setListenQueueSize:(id)listenQueueSize
|
||||
{
|
||||
if ([self tryLock])
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
_queueSize=[listenQueueSize intValue];
|
||||
if (_queueSize<1)
|
||||
_queueSize=1;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO
|
||||
};
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//NDFN
|
||||
-(id)announceNewConnection:(NSNotification*)notification
|
||||
{
|
||||
GSWDefaultAdaptorThread* newThread=nil;
|
||||
NSFileHandle* listenHandle=nil;
|
||||
NSFileHandle* inStream = nil;
|
||||
GSWTime requestTS=0;
|
||||
NSFileHandle *listenHandle=nil;
|
||||
NSFileHandle *inStream = nil;
|
||||
NSString* connRefusedMessage=nil;
|
||||
LOGObjectFnStart();
|
||||
|
||||
requestTS=GSWTime_now();
|
||||
// requestTS=GSWTime_now();
|
||||
|
||||
listenHandle=[notification object];
|
||||
|
||||
NSDebugDeepMLLog(@"info",@"listenHandle=%p",(void*)listenHandle);
|
||||
inStream = [[notification userInfo] objectForKey:@"NSFileHandleNotificationFileHandleItem"];
|
||||
// we want future Notifications.
|
||||
[listenHandle acceptConnectionInBackgroundAndNotify];
|
||||
|
||||
inStream = [[notification userInfo]objectForKey:@"NSFileHandleNotificationFileHandleItem"];
|
||||
NSDebugDeepMLog(@"%@ announceNewConnection notification=%@ "
|
||||
@"socketAddress=%@ [notification userInfo]=%p",
|
||||
GSCurrentThread(),
|
||||
notification,
|
||||
[inStream socketAddress],
|
||||
[notification userInfo]);
|
||||
|
||||
if (![self isConnectionAllowedWithHandle:inStream
|
||||
returnedMessage:&connRefusedMessage])
|
||||
{
|
||||
NSDebugDeepMLog(@"DESTROY the connection: conn refused - "
|
||||
@"%@ - A1 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
[GSWDefaultAdaptorThread sendConnectionRefusedResponseToStream:inStream
|
||||
withMessage:connRefusedMessage];
|
||||
inStream=nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDebugDeepMLLog(@"info",@"notification userInfo=%@",
|
||||
[notification userInfo]);
|
||||
NSDebugDeepMLog(@"%@ - A1 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
NSDebugDeepMLLog(@"%@ - A1 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
NSDebugDeepMLog(@"NEW CONN APP _selfLockn=%d _selfLock_thread_id=%@ "
|
||||
@"_globalLockn=%d _globalLock_thread_id=%@ "
|
||||
@"threads count=%d waitingThreads count=%d blocked=%d",
|
||||
(int)([GSWApplication application]->_selfLockn),
|
||||
([GSWApplication application]->_selfLock_thread_id),
|
||||
(int)([GSWApplication application]->_globalLockn),
|
||||
([GSWApplication application]->_globalLock_thread_id),
|
||||
[_threads count],
|
||||
[_waitingThreads count],
|
||||
_blocked);
|
||||
NSDebugDeepMLog(@"[waitingThreads count]=%d queueSize=%d",
|
||||
[_waitingThreads count],_queueSize);
|
||||
if ([_waitingThreads count]>=_queueSize)
|
||||
{
|
||||
//remove expired thread
|
||||
if ([self tryLock])
|
||||
{
|
||||
NSDebugMLog0(@"locked !");
|
||||
NS_DURING
|
||||
{
|
||||
int i=0;
|
||||
int waitingThreadsCount=[_waitingThreads count];
|
||||
GSWDefaultAdaptorThread* thread=nil;
|
||||
for(i=0;i<waitingThreadsCount;)
|
||||
{
|
||||
thread=[_waitingThreads objectAtIndex:i];
|
||||
if ([thread isExpired])
|
||||
{
|
||||
// [GSWDefaultAdaptorThread sendRetryLasterResponseToStream:[thread stream]];
|
||||
[_waitingThreads removeObjectAtIndex:i];
|
||||
}
|
||||
else
|
||||
i++;
|
||||
};
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
//TODO
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
};
|
||||
};
|
||||
if ([_waitingThreads count]>=_queueSize)
|
||||
{
|
||||
NSDebugDeepMLog(@"DESTROY the connection: too many conn - "
|
||||
@"%@ - A1 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
[GSWDefaultAdaptorThread sendRetryLasterResponseToStream:inStream];
|
||||
inStream=nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
//release done after lock !
|
||||
newThread=[[GSWDefaultAdaptorThread alloc] initWithApp:[GSWApplication application]
|
||||
withAdaptor:self
|
||||
withStream:inStream];
|
||||
if (newThread)
|
||||
{
|
||||
NSDebugLockMLog0(@"_newThread !");
|
||||
[newThread setRequestTS:requestTS];
|
||||
if ([self tryLock])
|
||||
{
|
||||
NSDebugLockMLog0(@"locked !");
|
||||
NS_DURING
|
||||
{
|
||||
NSDebugLockMLLog(@"low",
|
||||
@"[waitingThreads count]=%d [threads count]=%d",
|
||||
[_waitingThreads count],
|
||||
[_threads count]);
|
||||
if ([_threads count]<_workerThreadCount
|
||||
|| _isMultiThreadEnabled == NO)
|
||||
{
|
||||
[_threads addObject:newThread];
|
||||
NSDebugLockMLLog(@"trace",@"isMultiThreadEnabled=%d",
|
||||
_isMultiThreadEnabled);
|
||||
if (_isMultiThreadEnabled)
|
||||
{
|
||||
[GSWApplication statusLogWithFormat:@"%@ : Lauch Thread (Multi) %@",
|
||||
GSCurrentThread(),
|
||||
GSWTime_format(GSWTime_now())];
|
||||
|
||||
NSDebugLockMLLog(@"info",
|
||||
@"%@ : "
|
||||
@"Lauch Thread (Multi) %p",
|
||||
GSCurrentThread(),
|
||||
(void*)newThread);
|
||||
[NSThread detachNewThreadSelector:@selector(run:)
|
||||
toTarget:newThread
|
||||
withObject:nil];
|
||||
DESTROY(newThread);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Runit after
|
||||
/*
|
||||
[GSWApplication statusLogWithFormat:@"Lauch Thread (Mono)"];
|
||||
NSDebugMLLog(@"info",
|
||||
@"Lauch Thread (Mono) %p",
|
||||
(void*)_newThread);
|
||||
[_newThread run:nil];
|
||||
*/
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
[GSWApplication statusLogString:@"Set Thread to wait"];
|
||||
NSDebugLockMLLog(@"info",
|
||||
@"Set Thread to wait %p",
|
||||
(void*)newThread);
|
||||
[_waitingThreads addObject:newThread];
|
||||
DESTROY(newThread);
|
||||
};
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
//TODO
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
[self unlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
DESTROY(newThread);
|
||||
};
|
||||
};
|
||||
if (!_isMultiThreadEnabled && newThread)
|
||||
{
|
||||
|
||||
//NSDebugLockMLLog(@"info",
|
||||
// @"Launch Thread (Mono) %@ %p",
|
||||
// GSWTime_format(GSWTime_now()),
|
||||
// (void*)newThread);
|
||||
|
||||
[newThread run:nil];
|
||||
|
||||
DESTROY(newThread);
|
||||
|
||||
//NSDebugLockMLLog(@"info",
|
||||
// @"Stop Thread (Mono) %@",GSWTime_format(GSWTime_now()));
|
||||
};
|
||||
};
|
||||
};
|
||||
NSDebugLockMLLog(@"trace",@"Try Lock");
|
||||
if ([self tryLock])
|
||||
{
|
||||
BOOL accept=YES;//NEW[waitingThreads count]<queueSize;
|
||||
NSDebugLockMLLog(@"trace",@"Accept=%d",accept);
|
||||
NS_DURING
|
||||
{
|
||||
if (accept)
|
||||
{
|
||||
[listenHandle acceptConnectionInBackgroundAndNotify];
|
||||
_blocked=NO;
|
||||
NSDebugDeepMLog(@"ACCEPT %@ A2 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDebugDeepMLog(@"NOT ACCEPT %@ A2 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
};
|
||||
NSDebugLockMLog(@"%@ A2 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
//TODO
|
||||
_blocked=!accept;
|
||||
[self unlock];
|
||||
[localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
_blocked=!accept;
|
||||
printf("blocked=%d",_blocked);
|
||||
[self unlock];
|
||||
};
|
||||
NSDebugLockMLLog(@"trace",@"end announceNewConnection");
|
||||
NSDebugDeepMLog(@"END NEWCONN APP _selfLockn=%d _selfLock_thread_id=%@ "
|
||||
@"_globalLockn=%d _globalLock_thread_id=%@ "
|
||||
@"threads count=%d waitingThreads count=%d "
|
||||
@"blocked=%d acceptOK",
|
||||
(int)([GSWApplication application]->_selfLockn),
|
||||
([GSWApplication application]->_selfLock_thread_id),
|
||||
(int)([GSWApplication application]->_globalLockn),
|
||||
([GSWApplication application]->_globalLock_thread_id),
|
||||
[_threads count],
|
||||
[_waitingThreads count],
|
||||
_blocked);
|
||||
LOGObjectFnStop();
|
||||
return self;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)adaptorThreadExited:(GSWDefaultAdaptorThread*)adaptorThread
|
||||
returnedMessage:&connRefusedMessage]) {
|
||||
// don't waste any time
|
||||
[inStream closeFile];
|
||||
return;
|
||||
}
|
||||
|
||||
// SYNCHRONIZED(_selfLock)
|
||||
{
|
||||
LOGObjectFnStart();
|
||||
// NSDebugMLLog(@"trace",@"adaptorThreadExited");
|
||||
NSDebugDeepMLog0(@"adaptorThreadExited");
|
||||
NSDebugDeepMLog(@"EXIT APP _selfLockn=%d _selfLock_thread_id=%@ "
|
||||
@"_globalLockn=%d _globalLock_thread_id=%@ "
|
||||
@"threads count=%d waitingThreads count=%d blocked=%d",
|
||||
(int)([GSWApplication application]->_selfLockn),
|
||||
([GSWApplication application]->_selfLock_thread_id),
|
||||
(int)([GSWApplication application]->_globalLockn),
|
||||
([GSWApplication application]->_globalLock_thread_id),
|
||||
[_threads count],
|
||||
[_waitingThreads count],
|
||||
_blocked);
|
||||
|
||||
if ([self tryLock])
|
||||
{
|
||||
NSAutoreleasePool* pool=nil;
|
||||
#ifndef NDEBUG
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
NSDebugLockMLLog(@"low",
|
||||
@"remove thread %p",
|
||||
(void*)adaptorThread);
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
#endif
|
||||
NS_DURING
|
||||
{
|
||||
[adaptorThread retain];
|
||||
[adaptorThread autorelease];
|
||||
[_threads removeObject:adaptorThread];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
//TODO
|
||||
// [self unlock];
|
||||
// [localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
#ifndef NDEBUG
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
NSDebugLockMLLog(@"low",
|
||||
@"[waitingThreads count]=%d [threads count]=%d",
|
||||
[_waitingThreads count],
|
||||
[_threads count]);
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
#endif
|
||||
if ([_threads count]==0)
|
||||
{
|
||||
BOOL isApplicationRequestHandlingLocked=[[GSWApplication application] isRequestHandlingLocked];
|
||||
if (isApplicationRequestHandlingLocked)
|
||||
{
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
LOGSeriousError0(@"Application RequestHandling is LOCKED !!!");
|
||||
NSAssert(NO,@"Application RequestHandling is LOCKED !!!");//TODO-NOW
|
||||
[[GSWApplication application] terminate];
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
};
|
||||
};
|
||||
if ([_waitingThreads count]>0 && [_threads count]<_workerThreadCount)
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
GSWDefaultAdaptorThread* thread=nil;
|
||||
int waitingThreadsCount=[_waitingThreads count];
|
||||
while(!thread && waitingThreadsCount>0)
|
||||
{
|
||||
thread=[_waitingThreads objectAtIndex:0];
|
||||
if ([thread isExpired])
|
||||
{
|
||||
//[GSWDefaultAdaptorThread sendRetryLasterResponseToStream:[_thread stream]];
|
||||
thread=nil;
|
||||
}
|
||||
else
|
||||
[_threads addObject:thread];
|
||||
[_waitingThreads removeObjectAtIndex:0];
|
||||
waitingThreadsCount--;
|
||||
};
|
||||
if (thread)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
[GSWApplication statusLogString:@"Lauch waiting Thread"];
|
||||
NSDebugLockMLLog(@"info",
|
||||
@"Lauch waiting Thread %p",
|
||||
(void*)thread);
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
#endif
|
||||
if (_isMultiThreadEnabled)
|
||||
[NSThread detachNewThreadSelector:@selector(run:)
|
||||
toTarget:thread
|
||||
withObject:nil];
|
||||
else
|
||||
[thread run:nil];
|
||||
};
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
//TODO
|
||||
// [self unlock];
|
||||
// [localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
};
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
BOOL accept=[_waitingThreads count]<_queueSize;
|
||||
if (_blocked && accept)
|
||||
{
|
||||
NSDebugDeepMLog(@"ACCEPT AGAIN %@ A2 readInProgress=%d",
|
||||
GSCurrentThread(),
|
||||
(int)[_fileHandle readInProgress]);
|
||||
[_fileHandle acceptConnectionInBackgroundAndNotify];
|
||||
_blocked=NO;
|
||||
};
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
pool=[NSAutoreleasePool new];
|
||||
GSWLogMemCF("New NSAutoreleasePool: %p",pool);
|
||||
LOGException(@"%@ (%@)",
|
||||
localException,
|
||||
[localException reason]);
|
||||
GSWLogMemCF("Destroy NSAutoreleasePool: %p",pool);
|
||||
DESTROY(pool);
|
||||
//TODO
|
||||
// [self unlock];
|
||||
// [localException raise];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
[self unlock];
|
||||
};
|
||||
NSDebugDeepMLog(@"END EXIT APP _selfLockn=%d _selfLock_thread_id=%@ "
|
||||
@"_globalLockn=%d _globalLock_thread_id=%@ "
|
||||
@"threads count=%d waitingThreads count=%d blocked=%d",
|
||||
(int)([GSWApplication application]->_selfLockn),
|
||||
([GSWApplication application]->_selfLock_thread_id),
|
||||
([GSWApplication application]->_globalLockn),
|
||||
([GSWApplication application]->_globalLock_thread_id),
|
||||
[_threads count],
|
||||
[_waitingThreads count],
|
||||
_blocked);
|
||||
// (int)(((UnixFileHandle*)fileHandle)->acceptOK));
|
||||
NSDebugLockMLog(@"%@ B2 readInProgress=%d",
|
||||
GSCurrentThread(),(int)[_fileHandle readInProgress]);
|
||||
LOGObjectFnStop();
|
||||
};
|
||||
[_selfLock lock];
|
||||
int count = [_threads count];
|
||||
|
||||
if (count < _workerThreadCountMax) {
|
||||
_workOnHandle(inStream,self, _threads, _isMultiThreadEnabled);
|
||||
} else {
|
||||
_queueWorkOnHandle(inStream, _waitingThreads);
|
||||
}
|
||||
[_selfLock unlock];
|
||||
}
|
||||
|
||||
// END_SYNCHRONIZED;
|
||||
|
||||
}
|
||||
|
||||
-(NSFileHandle*)fileHandle
|
||||
{
|
||||
return _fileHandle;
|
||||
};
|
||||
//--------------------------------------------------------------------
|
||||
//NDFN
|
||||
}
|
||||
|
||||
-(id)announceBrokenConnection:(id)notification
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
NSDebugMLLog(@"trace",@"announceBrokenConnection");
|
||||
// [self shutDownConnectionWithSocket:[in_port _port_socket]];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// lock
|
||||
-(BOOL)tryLock
|
||||
{
|
||||
BOOL locked=NO;
|
||||
LOGObjectFnStart();
|
||||
NSDebugLockMLog(@"self=%p %@ TRYLOCK",
|
||||
self, GSCurrentThread());
|
||||
locked=LoggedTryLockBeforeDate(_selfLock,
|
||||
[NSDate dateWithTimeIntervalSinceNow:90]);
|
||||
NSDebugLockMLog(@"self=%p %@ TRYLOCK LOCKED ?",
|
||||
self, GSCurrentThread());
|
||||
LOGObjectFnStop();
|
||||
return locked;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// unlock
|
||||
-(void)unlock
|
||||
{
|
||||
LOGObjectFnStart();
|
||||
NSDebugLockMLog(@"self=%p %@ UNLOCK",
|
||||
self, GSCurrentThread());
|
||||
LoggedUnlock(_selfLock);
|
||||
NSDebugLockMLog(@"self=%p %@ UNLOCK UNLOCKED ?",
|
||||
self, GSCurrentThread());
|
||||
LOGObjectFnStop();
|
||||
};
|
||||
|
||||
-(BOOL)isConnectionAllowedWithHandle:(NSFileHandle*)handle
|
||||
returnedMessage:(NSString**)retMessage
|
||||
|
@ -791,18 +317,9 @@ int allow_severity = LOG_INFO;
|
|||
if ([_adaptorHost length]>0)
|
||||
{
|
||||
NSString* connAddress=[handle socketAddress];
|
||||
NSDebugMLog(@"HANDLE connAddress: %@ _adaptorHost=%@",
|
||||
connAddress,_adaptorHost);
|
||||
if ([connAddress isEqualToString:_adaptorHost])
|
||||
{
|
||||
[GSWApplication statusDebugWithFormat:
|
||||
@"ACCEPTED connection from: %@ (Allowed: %@)",
|
||||
connAddress,_adaptorHost];
|
||||
}
|
||||
else
|
||||
{
|
||||
[GSWApplication statusLogErrorWithFormat:
|
||||
@"REFUSED connection from: %@ (Allowed: %@)",
|
||||
|
||||
if ([connAddress isEqualToString:_adaptorHost] == NO) {
|
||||
[GSWApplication statusLogErrorWithFormat:@"REFUSED connection from: %@ (Allowed: %@)",
|
||||
connAddress,_adaptorHost];
|
||||
allowed=NO;
|
||||
if (retMessage)
|
||||
|
@ -849,6 +366,12 @@ int allow_severity = LOG_INFO;
|
|||
return allowed;
|
||||
};
|
||||
|
||||
// this is not changed after init, so there is no need for a lock
|
||||
- (BOOL) isMultiThreadEnabled
|
||||
{
|
||||
return _isMultiThreadEnabled;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/** GSWDefaultAdaptorThread.h - <title>GSWeb: Class GSWDefaultAdaptorThread</title>
|
||||
|
||||
Copyright (C) 1999-2003 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Manuel Guesdon <mguesdon@orange-concept.com>
|
||||
Date: Feb 1999
|
||||
|
||||
This file is part of the GNUstep Web Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**/
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef _GSWDefaultAdaptorThread_h__
|
||||
#define _GSWDefaultAdaptorThread_h__
|
||||
|
||||
|
||||
//==============================================================================
|
||||
@interface GSWDefaultAdaptorThread: NSObject
|
||||
{
|
||||
GSWApplication* _application;
|
||||
GSWAdaptor* _adaptor;
|
||||
NSFileHandle* _stream;
|
||||
NSAutoreleasePool* _pool;
|
||||
BOOL _keepAlive;
|
||||
NSRunLoop* _currentRunLoop;
|
||||
NSDate* _runLoopDate;
|
||||
BOOL _isMultiThread;
|
||||
|
||||
GSWTime _requestTS;
|
||||
GSWTime _creationTS;
|
||||
GSWTime _runTS;
|
||||
GSWTime _beginDispatchRequestTS;
|
||||
GSWTime _endDispatchRequestTS;
|
||||
GSWTime _sendResponseTS;
|
||||
NSString* _remoteAddress;
|
||||
int _requestNamingConv;//GSWNAMES_INDEX or WONAMES_INDEX
|
||||
}
|
||||
|
||||
-(id)initWithApp:(GSWApplication*)application
|
||||
withAdaptor:(GSWAdaptor*)adaptor
|
||||
withStream:(NSFileHandle*)stream;
|
||||
|
||||
-(void)run:(id)nothing;
|
||||
|
||||
-(GSWAdaptor*)adaptor;
|
||||
-(NSAutoreleasePool*)pool;
|
||||
-(void)setPool:(NSAutoreleasePool*)pool
|
||||
destroyLast:(BOOL)destroy;
|
||||
|
||||
-(BOOL)readRequestReturnedRequestLine:(NSString**)requestLine
|
||||
returnedHeaders:(NSDictionary**)headers
|
||||
returnedData:(NSData**)data;
|
||||
-(GSWRequest*)createRequestFromRequestLine:(NSString*)requestLine
|
||||
headers:(NSDictionary*)headers
|
||||
data:(NSData*)data;
|
||||
-(void)sendResponse:(GSWResponse*)response;
|
||||
-(void)threadExited;
|
||||
+(id)threadExited:(NSNotification*)notif;
|
||||
-(GSWTime)creationTS;
|
||||
-(BOOL)isExpired;
|
||||
-(void)setRequestTS:(GSWTime)requestTS;
|
||||
+(void)sendResponse:(GSWResponse*)response
|
||||
toStream:(NSFileHandle*)aStream
|
||||
withNamingConv:(int)requestNamingConv
|
||||
withAdditionalHeaderLines:(NSArray*)addHeaders
|
||||
withRemoteAddress:(NSString*)remoteAddress;
|
||||
|
||||
+(void)sendRetryLasterResponseToStream:(NSFileHandle*)stream;
|
||||
+(void)sendConnectionRefusedResponseToStream:(NSFileHandle*)stream
|
||||
withMessage:(NSString*)message;
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -1,884 +0,0 @@
|
|||
/** GSWDefaultAdaptorThread.m - <title>GSWeb: Class GSWDefaultAdaptorThread</title>
|
||||
|
||||
Copyright (C) 1999-2004 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Manuel Guesdon <mguesdon@orange-concept.com>
|
||||
Date: Feb 1999
|
||||
|
||||
$Revision$
|
||||
$Date$
|
||||
$Id$
|
||||
|
||||
<abstract></abstract>
|
||||
|
||||
This file is part of the GNUstep Web Library.
|
||||
|
||||
<license>
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
</license>
|
||||
**/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
RCS_ID("$Id$")
|
||||
|
||||
#include "GSWeb.h"
|
||||
#include <unistd.h>
|
||||
#include <math.h> //for fabs
|
||||
#include "NSNonBlockingFileHandle.h"
|
||||
#define ADAPTOR_THREAD_TIME_OUT (5*60) // in seconds. threads waiting for more than 5 minutes are not processed
|
||||
|
||||
static SEL objectAtIndexSEL=NULL;
|
||||
static SEL appendDataSEL=NULL;
|
||||
static NSData* lineFeedData=nil;
|
||||
//====================================================================
|
||||
@implementation GSWDefaultAdaptorThread
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSWDefaultAdaptorThread class])
|
||||
{
|
||||
objectAtIndexSEL=@selector(objectAtIndex:);
|
||||
appendDataSEL=@selector(appendData:);
|
||||
ASSIGN(lineFeedData,([[NSString stringWithString:@"\n"]
|
||||
dataUsingEncoding:NSASCIIStringEncoding]));
|
||||
};
|
||||
};
|
||||
//--------------------------------------------------------------------
|
||||
-(id)init
|
||||
{
|
||||
if ((self=[super init]))
|
||||
{
|
||||
_creationTS=GSWTime_now();
|
||||
_requestNamingConv=GSWebNamingConv;//GSWNAMES_INDEX or WONAMES_INDEX
|
||||
};
|
||||
return self;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(id)initWithApp:(GSWApplication*)application
|
||||
withAdaptor:(GSWAdaptor*)adaptor
|
||||
withStream:(NSFileHandle*)stream
|
||||
{
|
||||
if ((self=[self init]))
|
||||
{
|
||||
_application=application;
|
||||
_adaptor=adaptor;
|
||||
ASSIGN(_stream,stream);
|
||||
_keepAlive=NO;
|
||||
_isMultiThread=[adaptor isMultiThreadEnabled];
|
||||
};
|
||||
return self;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)dealloc
|
||||
{
|
||||
DESTROY(_stream);
|
||||
DESTROY(_remoteAddress);
|
||||
DESTROY(_pool);
|
||||
|
||||
[super dealloc];
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(GSWAdaptor*)adaptor
|
||||
{
|
||||
return _adaptor;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(NSAutoreleasePool*)pool
|
||||
{
|
||||
return _pool;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)setPool:(NSAutoreleasePool*)pool
|
||||
destroyLast:(BOOL)destroy
|
||||
{
|
||||
if (destroy) {
|
||||
DESTROY(_pool);
|
||||
};
|
||||
_pool=pool;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)run:(id)nothing
|
||||
{
|
||||
BOOL requestOk=NO;
|
||||
NSMutableDictionary* threadDictionary=nil;
|
||||
NSString* requestLine=nil;
|
||||
NSDictionary* headers=nil;
|
||||
NSData* data=nil;
|
||||
|
||||
DESTROY(_pool);
|
||||
_pool=[NSAutoreleasePool new];
|
||||
#ifdef GSWDEBUG_DEEP
|
||||
[GSWApplication logString:@"pool allocated!"];
|
||||
#endif
|
||||
|
||||
_runTS=GSWTime_now();
|
||||
_beginDispatchRequestTS=GSWTime_zero();
|
||||
_endDispatchRequestTS=GSWTime_zero();
|
||||
_sendResponseTS=GSWTime_zero();
|
||||
|
||||
#ifdef GSWDEBUG_DEEP
|
||||
[GSWApplication statusLogString:@"Thread run START"];
|
||||
#endif
|
||||
if (_isMultiThread)
|
||||
{
|
||||
threadDictionary=GSCurrentThreadDictionary();
|
||||
[threadDictionary setObject:self
|
||||
forKey:GSWThreadKey_DefaultAdaptorThread];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:[self class]
|
||||
selector:@selector(threadExited:)
|
||||
name:NSThreadWillExitNotification
|
||||
object:[NSThread currentThread]];
|
||||
/*
|
||||
[NotificationDispatcher addObserver:[self class]
|
||||
selector:@selector(threadExited:)
|
||||
name:NSThreadWillExitNotification
|
||||
object:[NSThread currentThread]];
|
||||
*/
|
||||
};
|
||||
NS_DURING
|
||||
{
|
||||
requestOk=[self readRequestReturnedRequestLine:&requestLine
|
||||
returnedHeaders:&headers
|
||||
returnedData:&data];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"GSWDefaultAdaptorThread: readRequestFromStream Exception:%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
if (!requestOk)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
GSWRequest* request=nil;
|
||||
GSWResponse* response=nil;
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
request=[self createRequestFromRequestLine:requestLine
|
||||
headers:headers
|
||||
data:data];
|
||||
//NSLog(@"%s %@",__PRETTY_FUNCTION__, request);
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"GSWDefaultAdaptorThread: createRequestFromData Exception:%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
if (request)
|
||||
{
|
||||
//call application resourceRequestHandlerKey (retourne wr)
|
||||
//call requets requestHandlerKey (retorune nil)
|
||||
_beginDispatchRequestTS=GSWTime_now();
|
||||
NS_DURING
|
||||
{
|
||||
response=[_application dispatchRequest:request];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
BOOL isApplicationRequestHandlingLocked=[_application isRequestHandlingLocked];
|
||||
LOGException(@"GSWDefaultAdaptorThread: dispatchRequest Exception:%@ (%@)%s",
|
||||
localException,
|
||||
[localException reason],
|
||||
isApplicationRequestHandlingLocked ? " Request Handling Locked !" : "");
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
_endDispatchRequestTS=GSWTime_now();
|
||||
if (!response)
|
||||
{
|
||||
response=[GSWResponse responseWithMessage:@"Application returned no response"
|
||||
inContext:nil
|
||||
forRequest:request];
|
||||
[response _finalizeInContext:nil]; //DO Call _finalizeInContext: !
|
||||
};
|
||||
if (response)
|
||||
{
|
||||
RETAIN(response);
|
||||
NS_DURING
|
||||
{
|
||||
[self sendResponse:response];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
LOGException(@"GSWDefaultAdaptorThread: sendResponse Exception:%@ (%@)",
|
||||
localException,
|
||||
[localException reason],
|
||||
[localException userInfo]);
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
AUTORELEASE(response);
|
||||
};
|
||||
};
|
||||
};
|
||||
[_application threadWillExit];
|
||||
if (_isMultiThread)
|
||||
{
|
||||
NSAssert([NSThread isMultiThreaded],@"No MultiThread !");
|
||||
[NSThread exit]; //???
|
||||
}
|
||||
else
|
||||
[self threadExited];
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)threadExited
|
||||
{
|
||||
[_adaptor adaptorThreadExited:self];
|
||||
|
||||
[self setPool:nil
|
||||
destroyLast:YES];
|
||||
[GSWApp debugAdaptorThreadExited];
|
||||
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
+(id)threadExited:(NSNotification*)notif
|
||||
{
|
||||
NSThread* thread=nil;
|
||||
NSMutableDictionary* threadDict=nil;
|
||||
GSWDefaultAdaptorThread* adaptorThread=nil;
|
||||
|
||||
NSAssert([NSThread isMultiThreaded],@"No MultiThread !");
|
||||
thread=[notif object];
|
||||
threadDict = [thread threadDictionary];
|
||||
adaptorThread=[threadDict objectForKey:GSWThreadKey_DefaultAdaptorThread];
|
||||
[threadDict removeObjectForKey:GSWThreadKey_DefaultAdaptorThread];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSThreadWillExitNotification
|
||||
object:thread];
|
||||
/* [NotificationDispatcher removeObserver:self
|
||||
name:NSThreadWillExitNotification
|
||||
object:_thread];
|
||||
*/
|
||||
[adaptorThread threadExited];
|
||||
|
||||
return nil; //??
|
||||
};
|
||||
|
||||
|
||||
|
||||
NSMutableArray* unpackData(NSMutableData* data)
|
||||
{
|
||||
NSMutableArray* lines = [NSMutableArray new];
|
||||
int length = [data length];
|
||||
|
||||
if (length>0) {
|
||||
NSRange range=NSMakeRange(0,0);
|
||||
int i=0;
|
||||
int lastIndex=0;
|
||||
NSString * tmpString = nil;
|
||||
char* dataBytes=(char*)[data mutableBytes];
|
||||
BOOL endHeaders=NO;
|
||||
while(!endHeaders && i<length)
|
||||
{
|
||||
if (dataBytes[i]=='\n') {
|
||||
range.location=lastIndex;
|
||||
range.length=(i-range.location);
|
||||
lastIndex = i+1;
|
||||
|
||||
if (range.length > 1) {
|
||||
tmpString=[[NSString alloc] initWithData: [data subdataWithRange:range]
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
[lines addObject: [tmpString stringByTrimmingSpaces]];
|
||||
[tmpString release];
|
||||
} else {
|
||||
endHeaders=YES;
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [lines autorelease];
|
||||
}
|
||||
|
||||
|
||||
- (NSDictionary*) unpackHeaders:(NSArray*) lines
|
||||
{
|
||||
NSMutableDictionary* headers = [NSMutableDictionary dictionary];
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
NSArray* prevValue = nil;
|
||||
|
||||
if ((lines) && ([lines count] > 1)) {
|
||||
count = [lines count];
|
||||
for (i=1;i<count-1;i++) {
|
||||
NSString * tmpLine = [lines objectAtIndex:i];
|
||||
NSArray * components = [tmpLine componentsSeparatedByString:@": "];
|
||||
NSString * value = nil;
|
||||
NSArray * newValue = nil;
|
||||
NSString * key = nil;
|
||||
|
||||
if ((components) && ([components count] == 2)) {
|
||||
value = [components objectAtIndex:1];
|
||||
key = [components objectAtIndex:0];
|
||||
key = [[key stringByTrimmingSpaces] lowercaseString];
|
||||
|
||||
if ([key isEqualToString:GSWHTTPHeader_AdaptorVersion[GSWNAMES_INDEX]]
|
||||
|| [key isEqualToString:GSWHTTPHeader_ServerName[GSWNAMES_INDEX]]) {
|
||||
_requestNamingConv=GSWNAMES_INDEX;
|
||||
goto keyDone;
|
||||
}
|
||||
if ([key isEqualToString:GSWHTTPHeader_AdaptorVersion[WONAMES_INDEX]]
|
||||
|| [key isEqualToString:GSWHTTPHeader_ServerName[WONAMES_INDEX]]) {
|
||||
_requestNamingConv=WONAMES_INDEX;
|
||||
goto keyDone;
|
||||
}
|
||||
|
||||
keyDone:
|
||||
|
||||
prevValue=[headers objectForKey:key];
|
||||
if (prevValue) {
|
||||
newValue=[prevValue arrayByAddingObject:value];
|
||||
} else {
|
||||
newValue=[NSArray arrayWithObject:value];
|
||||
}
|
||||
|
||||
[headers setObject: newValue
|
||||
forKey: key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
- (NSData*) _readPostDataMultipart:(BOOL) multip boundary:(NSString*) boundary
|
||||
{
|
||||
|
||||
#define UPLOAD_LIMIT 1024*1024*10 // 10 MB
|
||||
#define TIME_LIMIT 15 // seconds
|
||||
|
||||
time_t starttime, now;
|
||||
BOOL crSeen = NO;
|
||||
BOOL nlSeen = NO;
|
||||
BOOL crnlSeen = NO;
|
||||
int crlfCount = 1;
|
||||
int tmpPos = 0;
|
||||
unsigned bytesSinceNewLine = 0;
|
||||
BOOL isElapsed = NO;
|
||||
NSMutableData* allMimeData = (NSMutableData*)[NSMutableData data];
|
||||
NSData* boundaryData = nil;
|
||||
unsigned boundaryLen = NSNotFound;
|
||||
|
||||
char buffer[5];
|
||||
char buffer1[100];
|
||||
|
||||
if (multip) {
|
||||
NSString * totalString = [[@"--" stringByAppendingString: boundary] stringByAppendingString:@"--"];
|
||||
boundaryLen = [totalString length];
|
||||
boundaryData = [totalString dataUsingEncoding: NSUTF8StringEncoding];
|
||||
}
|
||||
time(&starttime);
|
||||
|
||||
NS_DURING
|
||||
|
||||
while ((! isElapsed) && ([allMimeData length] <= UPLOAD_LIMIT) && (crlfCount > 0)) {
|
||||
NSData* dataBlock = [_stream readDataOfLength:1];
|
||||
if ((dataBlock) && ([dataBlock length])) {
|
||||
[dataBlock getBytes:buffer];
|
||||
if (buffer[0] == 0xd) {
|
||||
crSeen = YES;
|
||||
time(&now);
|
||||
isElapsed = ((now - starttime) > TIME_LIMIT);
|
||||
} else {
|
||||
if (buffer[0] == 0xa) {
|
||||
nlSeen = YES;
|
||||
} else {
|
||||
crSeen = NO;
|
||||
nlSeen = NO;
|
||||
crnlSeen = NO;
|
||||
bytesSinceNewLine++;
|
||||
}
|
||||
}
|
||||
|
||||
if (crlfCount > 0) {
|
||||
[allMimeData appendData:dataBlock];
|
||||
// printf("%c (%x)\n", buffer[0], buffer[0]); // cr (0d) + nl (0a)
|
||||
}
|
||||
|
||||
if (crSeen && nlSeen) {
|
||||
crnlSeen = YES;
|
||||
crSeen = NO;
|
||||
nlSeen = NO;
|
||||
|
||||
if (boundaryLen == bytesSinceNewLine) {
|
||||
NSRange range = NSMakeRange([allMimeData length]-2-boundaryLen, boundaryLen);
|
||||
NSData * tmpData = [allMimeData subdataWithRange: range];
|
||||
|
||||
if ([tmpData isEqual: boundaryData]) {
|
||||
crlfCount = 0;
|
||||
}
|
||||
}
|
||||
tmpPos = [allMimeData length];
|
||||
if (multip == NO) {
|
||||
crlfCount = 0;
|
||||
}
|
||||
|
||||
bytesSinceNewLine = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NS_HANDLER
|
||||
NSLog(@"%@", [localException reason]);
|
||||
NS_ENDHANDLER
|
||||
|
||||
if ([allMimeData length] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return allMimeData;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/** read request from crrent stream and put request line, headers and data in
|
||||
'requestLinePtr', 'headersPtr', 'dataPtr'. Returns YES if it's OK, NO otherwise
|
||||
**/
|
||||
-(BOOL)readRequestReturnedRequestLine:(NSString**)requestLinePtr
|
||||
returnedHeaders:(NSDictionary**)headersPtr
|
||||
returnedData:(NSData**)dataPtr
|
||||
{
|
||||
NSMutableData* pendingData=nil;
|
||||
NSData* dataBlock=nil;
|
||||
NSData* dataBlock2=nil;
|
||||
int totalBytes=0;
|
||||
int tries=0;
|
||||
int dataBlockLength=0;
|
||||
int contentLength=-1;
|
||||
BOOL newLineSeen=NO;
|
||||
BOOL allDataRead=NO;
|
||||
BOOL isElapsed=NO;
|
||||
BOOL headersDone=NO;
|
||||
NSArray *listItems = nil;
|
||||
NSMutableData * allMimeData = nil;
|
||||
NSDictionary * headerDict = nil;
|
||||
|
||||
#define MAX_HEADER_BYTES 1000
|
||||
|
||||
time_t starttime, now;
|
||||
|
||||
if (!_stream)
|
||||
{
|
||||
ExceptionRaise0(@"GSWDefaultAdaptorThread",@"no stream");
|
||||
}
|
||||
|
||||
time(&starttime);
|
||||
struct timeval timeout;
|
||||
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
setsockopt([_stream fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout));
|
||||
|
||||
while (((allDataRead == NO) && (isElapsed == NO)) && (totalBytes < MAX_HEADER_BYTES)) {
|
||||
char buffer[5];
|
||||
|
||||
dataBlock= [_stream readDataOfLength:1];
|
||||
dataBlockLength=[dataBlock length];
|
||||
|
||||
if (dataBlockLength>0) {
|
||||
[dataBlock getBytes:buffer];
|
||||
|
||||
if ((buffer[0] == 0xa)) {
|
||||
if ((newLineSeen)) {
|
||||
headersDone = YES;
|
||||
}
|
||||
newLineSeen = YES;
|
||||
} else {
|
||||
if ((buffer[0] != 0xd)) { // cr
|
||||
newLineSeen = NO;
|
||||
}
|
||||
}
|
||||
buffer[1] = '\0';
|
||||
|
||||
if (headersDone) {
|
||||
NSArray * myArray = nil;
|
||||
|
||||
listItems = unpackData(pendingData);
|
||||
headerDict = [self unpackHeaders:listItems];
|
||||
*headersPtr = headerDict;
|
||||
myArray = [headerDict objectForKey:@"content-length"];
|
||||
|
||||
if ((myArray) && ([myArray count])) {
|
||||
contentLength = [[myArray objectAtIndex:0] intValue];
|
||||
//
|
||||
if (contentLength > 0) {
|
||||
if (!allMimeData) {
|
||||
allMimeData = (NSMutableData*)[NSMutableData data];
|
||||
}
|
||||
while ((contentLength > 0) && (! isElapsed)) {
|
||||
dataBlock2 = [_stream readDataOfLength: contentLength];
|
||||
[allMimeData appendData:dataBlock2];
|
||||
contentLength = contentLength-[dataBlock2 length];
|
||||
time(&now);
|
||||
isElapsed = ((now - starttime) > 30);
|
||||
}
|
||||
}
|
||||
//
|
||||
} else { // no content length info
|
||||
myArray = [headerDict objectForKey:@"content-type"];
|
||||
if ((myArray) && ([myArray count])) {
|
||||
NSString * multiStr = [myArray objectAtIndex:0];
|
||||
BOOL multipart = ([multiStr hasPrefix:@"multipart/form-data;"]);
|
||||
NSString * boundStr = nil;
|
||||
if (multipart) {
|
||||
boundStr = [multiStr substringFromIndex:30];
|
||||
}
|
||||
|
||||
allMimeData = [self _readPostDataMultipart: multipart boundary: boundStr];
|
||||
}
|
||||
}
|
||||
allDataRead = YES;
|
||||
} else {
|
||||
totalBytes+=dataBlockLength;
|
||||
if (!pendingData)
|
||||
pendingData=(NSMutableData*)[NSMutableData data];
|
||||
[pendingData appendData:dataBlock];
|
||||
tries=0;
|
||||
}
|
||||
} else {
|
||||
if (((totalBytes>2) && (tries>3)) && (newLineSeen)) {
|
||||
allDataRead = YES;
|
||||
}
|
||||
tries++;
|
||||
}
|
||||
}
|
||||
|
||||
if (allMimeData) {
|
||||
*dataPtr = [[allMimeData retain] autorelease];
|
||||
}
|
||||
|
||||
// check headers for contents?
|
||||
if (!headerDict) {
|
||||
*requestLinePtr=nil;
|
||||
*headersPtr=nil;
|
||||
*dataPtr=nil;
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
*requestLinePtr = [listItems objectAtIndex:0];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/** return a created request build with 'requestLine', 'headers' and 'data' **/
|
||||
-(GSWRequest*)createRequestFromRequestLine:(NSString*)requestLine
|
||||
headers:(NSDictionary*)headers
|
||||
data:(NSData*)data
|
||||
{
|
||||
GSWRequest* request=nil;
|
||||
int requestLineLength=0;
|
||||
|
||||
requestLineLength=[requestLine length];
|
||||
if (requestLineLength==0)
|
||||
{
|
||||
ExceptionRaise(@"GSWDefaultAdaptorThread",
|
||||
@"bad request first line: '%@'",
|
||||
requestLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSRange spaceRange;
|
||||
NSRange urlRange;
|
||||
NSString* method=nil;
|
||||
NSString* url=nil;
|
||||
NSString* protocolString=nil;
|
||||
NSArray* protocol=nil;
|
||||
|
||||
spaceRange=[requestLine rangeOfString:@" "];
|
||||
if (spaceRange.length==0 || spaceRange.location+spaceRange.length>=requestLineLength)
|
||||
{
|
||||
ExceptionRaise(@"GSWDefaultAdaptorThread",
|
||||
@"bad request first line: No method or no protocol '%@'",
|
||||
requestLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
method=[requestLine substringToIndex:spaceRange.location];
|
||||
urlRange.location=spaceRange.location+spaceRange.length;//+1 to skip space
|
||||
spaceRange=[requestLine rangeOfString:@" "
|
||||
options:NSBackwardsSearch
|
||||
range:NSMakeRange(urlRange.location,requestLineLength-urlRange.location)];
|
||||
if (spaceRange.length==0 || spaceRange.location<=urlRange.location)
|
||||
{
|
||||
ExceptionRaise(@"GSWDefaultAdaptorThread",
|
||||
@"bad request first line: No protocol or no url '%@'",
|
||||
requestLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
protocolString=[requestLine substringFromIndex:spaceRange.location+spaceRange.length];
|
||||
protocol=[protocolString componentsSeparatedByString:@"/"];
|
||||
urlRange.length=spaceRange.location-urlRange.location;
|
||||
url=[requestLine substringFromRange:urlRange];
|
||||
|
||||
if ([protocol count]!=2)
|
||||
{
|
||||
ExceptionRaise0(@"GSWDefaultAdaptorThread",@"bad request first line (HTTP)");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* httpVersion=[protocol objectAtIndex:1];
|
||||
if ((httpVersion) && ([httpVersion length] > 3)) {
|
||||
httpVersion = [httpVersion substringToIndex:3];
|
||||
}
|
||||
request=[_application createRequestWithMethod:method
|
||||
uri:url
|
||||
httpVersion:httpVersion
|
||||
headers:headers
|
||||
content:data
|
||||
userInfo:nil];
|
||||
/* };*/
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/** Send response 'response' to current stream using current naming convention **/
|
||||
-(void)sendResponse:(GSWResponse*)response
|
||||
{
|
||||
NSString* anHeader=nil;
|
||||
|
||||
_sendResponseTS=GSWTime_now();
|
||||
|
||||
// Based on requestTS
|
||||
anHeader=[NSString stringWithFormat:@"%@: applicationThreadCreation=+%0.3fs applicationThreadRun=+%0.3fs applicationBeginDispatchRequest=+%0.3fs applicationEndDispatchRequest=+%0.3fs applicationDispatchRequest=%0.3fs applicationBeginSendResponse=+%0.3fs applicationTimeSpent=%0.3fs",
|
||||
GSWHTTPHeader_AdaptorStats[_requestNamingConv],
|
||||
GSWTime_floatSec(_creationTS-_requestTS),
|
||||
GSWTime_floatSec(_runTS-_requestTS),
|
||||
GSWTime_floatSec(_beginDispatchRequestTS-_requestTS),
|
||||
GSWTime_floatSec(_endDispatchRequestTS-_requestTS),
|
||||
GSWTime_floatSec(_endDispatchRequestTS-_beginDispatchRequestTS),
|
||||
GSWTime_floatSec(_sendResponseTS-_requestTS),
|
||||
GSWTime_floatSec(_sendResponseTS-_requestTS)];
|
||||
|
||||
[[self class]sendResponse:response
|
||||
toStream:_stream
|
||||
withNamingConv:_requestNamingConv
|
||||
withAdditionalHeaderLines:[NSArray arrayWithObject:anHeader]
|
||||
withRemoteAddress:_remoteAddress];
|
||||
ASSIGN(_stream,nil);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/** send response 'response' to stream 'aStream' using naming convention 'requestNamingConv'
|
||||
Note: the stream is closed at the end of the write
|
||||
**/
|
||||
+(void)sendResponse:(GSWResponse*)response
|
||||
toStream:(NSFileHandle*)aStream
|
||||
withNamingConv:(int)requestNamingConv
|
||||
withAdditionalHeaderLines:(NSArray*)addHeaders
|
||||
withRemoteAddress:(NSString*)remoteAddress
|
||||
{
|
||||
BOOL ok=YES;
|
||||
|
||||
[response willSend];
|
||||
if (response)
|
||||
{
|
||||
IMP objectAtIndexIMP=NULL;
|
||||
int addHeadersCount=[addHeaders count];
|
||||
int headerN=0;
|
||||
int headerNForKey=0;
|
||||
NSMutableData* responseData=(NSMutableData*)[NSMutableData data];
|
||||
IMP appendDataIMP=[responseData methodForSelector:appendDataSEL];
|
||||
NSArray* headerKeys=[response headerKeys];
|
||||
int headerKeysCount=[headerKeys count];
|
||||
NSArray* headersForKey=nil;
|
||||
NSString* key=nil;
|
||||
NSString* anHeader=nil;
|
||||
NSString* head=[NSString stringWithFormat:@"HTTP/%@ %d %@ %@\n",
|
||||
[response httpVersion],
|
||||
[response status],
|
||||
GSWHTTPHeader_Response_OK,
|
||||
GSWHTTPHeader_Response_HeaderLineEnd[requestNamingConv]];
|
||||
|
||||
(*appendDataIMP)(responseData,appendDataSEL,
|
||||
[head dataUsingEncoding:NSASCIIStringEncoding]);
|
||||
|
||||
objectAtIndexIMP=[headerKeys methodForSelector:objectAtIndexSEL];
|
||||
for(headerN=0;headerN<headerKeysCount;headerN++)
|
||||
{
|
||||
int headersForKeyCount=0;
|
||||
key=(*objectAtIndexIMP)(headerKeys,objectAtIndexSEL,headerN);
|
||||
headersForKey=[response headersForKey:key];
|
||||
headersForKeyCount=[headersForKey count];
|
||||
for(headerNForKey=0;headerNForKey<headersForKeyCount;headerNForKey++)
|
||||
{
|
||||
anHeader=[NSString stringWithFormat:@"%@: %@\n",
|
||||
key,
|
||||
[headersForKey objectAtIndex:headerNForKey]];
|
||||
|
||||
(*appendDataIMP)(responseData,appendDataSEL,
|
||||
[anHeader dataUsingEncoding:NSASCIIStringEncoding]);
|
||||
};
|
||||
};
|
||||
|
||||
objectAtIndexIMP=[addHeaders methodForSelector:objectAtIndexSEL];
|
||||
for(headerN=0;headerN<addHeadersCount;headerN++)
|
||||
{
|
||||
(*appendDataIMP)(responseData,appendDataSEL,
|
||||
[(*objectAtIndexIMP)(addHeaders,objectAtIndexSEL,headerN)
|
||||
dataUsingEncoding:NSASCIIStringEncoding]);
|
||||
(*appendDataIMP)(responseData,appendDataSEL,lineFeedData);
|
||||
};
|
||||
|
||||
// Headers/Content separator
|
||||
(*appendDataIMP)(responseData,appendDataSEL,lineFeedData);
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
[aStream writeData:responseData];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
ok=NO;
|
||||
LOGException(@"GSWDefaultAdaptorThread: sendResponse Exception:%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
NSDebugMLog(@"EXCEPTION GSWDefaultAdaptorThread: sendResponse Exception:%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
[GSWApplication statusLogString:@"\nException while sending response\n"];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
|
||||
if (ok)
|
||||
{
|
||||
NSData* responseContent=[response content];
|
||||
int responseContentLength=[responseContent length];
|
||||
if (responseContentLength>0)
|
||||
{
|
||||
[responseData setLength:responseContentLength];
|
||||
[responseData setData:responseContent];
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
[aStream writeData:responseData];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
ok=NO;
|
||||
LOGException(@"GSWDefaultAdaptorThread: sendResponse Exception:%@ (%@)",
|
||||
localException,[localException reason]);
|
||||
[GSWApplication statusLogString:@"\nException while sending response\n"];
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
};
|
||||
};
|
||||
};
|
||||
[aStream closeFile];
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/** Returns thread creation TS **/
|
||||
-(GSWTime)creationTS
|
||||
{
|
||||
return _creationTS;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
/** Returns YES if the thread has expired (timed out) **/
|
||||
-(BOOL)isExpired
|
||||
{
|
||||
time_t elapsedSeconds=GSWTime_secPart(GSWTime_now()-_creationTS);
|
||||
BOOL isExpired=(elapsedSeconds>ADAPTOR_THREAD_TIME_OUT);
|
||||
|
||||
return isExpired;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)setRequestTS:(GSWTime)requestTS
|
||||
{
|
||||
_requestTS=requestTS;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(NSFileHandle*)stream
|
||||
{
|
||||
return _stream;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
+(void)sendRetryLasterResponseToStream:(NSFileHandle*)stream
|
||||
{
|
||||
GSWResponse* response=nil;
|
||||
NSAutoreleasePool* pool=nil;
|
||||
pool=[NSAutoreleasePool new];
|
||||
|
||||
response=[GSWResponse responseWithMessage:@"Temporary unavailable"
|
||||
inContext:nil
|
||||
forRequest:nil
|
||||
forceFinalize:YES];
|
||||
[response setStatus:503];//503=Service Unavailable
|
||||
|
||||
[self sendResponse:response
|
||||
toStream:stream
|
||||
withNamingConv:GSWNAMES_INDEX
|
||||
withAdditionalHeaderLines:nil
|
||||
withRemoteAddress:nil];
|
||||
|
||||
DESTROY(pool);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
+(void)sendConnectionRefusedResponseToStream:(NSFileHandle*)stream
|
||||
withMessage:(NSString*)message
|
||||
{
|
||||
GSWResponse* response=nil;
|
||||
NSAutoreleasePool* pool=nil;
|
||||
pool=[NSAutoreleasePool new];
|
||||
|
||||
response=[GSWResponse responseWithMessage:message
|
||||
inContext:nil
|
||||
forRequest:nil
|
||||
forceFinalize:YES];
|
||||
[response setStatus:503];//503=Service Unavailable
|
||||
|
||||
[self sendResponse:response
|
||||
toStream:stream
|
||||
withNamingConv:GSWNAMES_INDEX
|
||||
withAdditionalHeaderLines:nil
|
||||
withRemoteAddress:nil];
|
||||
|
||||
DESTROY(pool);
|
||||
};
|
||||
|
||||
@end
|
||||
|
|
@ -44,5 +44,78 @@
|
|||
#endif
|
||||
|
||||
|
||||
/*
|
||||
The following macros are for use of locks together with exception handling.
|
||||
A synchronized block is properly 'unlocked' even if an exception occures.
|
||||
It is used this way:
|
||||
|
||||
SYNCHRONIZED(MyObject) {
|
||||
THROW(MyException..);
|
||||
}
|
||||
END_SYNCHRONIZED;
|
||||
|
||||
Where MyObject must be an object that conforms to the NSObject and NSLocking
|
||||
protocol.
|
||||
This is much different to
|
||||
|
||||
[MyObject lock];
|
||||
{
|
||||
THROW(MyException..);
|
||||
}
|
||||
[MyObject unlock];
|
||||
|
||||
which leaves the lock locked when an exception happens.
|
||||
*/
|
||||
|
||||
#if defined(DEBUG_SYNCHRONIZED)
|
||||
|
||||
#define SYNCHRONIZED(__lock__) \
|
||||
{ \
|
||||
id<NSObject,NSLocking> __syncLock__ = [__lock__ retain]; \
|
||||
[__syncLock__ lock]; \
|
||||
fprintf(stderr, "0x%08X locked in %s.\n", \
|
||||
(unsigned)__syncLock__, __PRETTY_FUNCTION__); \
|
||||
NS_DURING {
|
||||
|
||||
#define END_SYNCHRONIZED \
|
||||
} \
|
||||
NS_HANDLER { \
|
||||
fprintf(stderr, "0x%08X exceptional unlock in %s exception %s.\n", \
|
||||
(unsigned)__syncLock__, __PRETTY_FUNCTION__,\
|
||||
[[localException description] cString]); \
|
||||
[__syncLock__ unlock]; \
|
||||
[__syncLock__ release]; __syncLock__ = nil; \
|
||||
[localException raise]; \
|
||||
} \
|
||||
NS_ENDHANDLER; \
|
||||
fprintf(stderr, "0x%08X unlock in %s.\n", \
|
||||
(unsigned)__syncLock__, __PRETTY_FUNCTION__); \
|
||||
[__syncLock__ unlock]; \
|
||||
[__syncLock__ release]; __syncLock__ = nil; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define SYNCHRONIZED(__lock__) \
|
||||
{ \
|
||||
id<NSObject,NSLocking> __syncLock__ = [__lock__ retain]; \
|
||||
[__syncLock__ lock]; \
|
||||
NS_DURING {
|
||||
|
||||
#define END_SYNCHRONIZED \
|
||||
} \
|
||||
NS_HANDLER { \
|
||||
[__syncLock__ unlock]; \
|
||||
[__syncLock__ release]; \
|
||||
[localException raise]; \
|
||||
} \
|
||||
NS_ENDHANDLER; \
|
||||
[__syncLock__ unlock]; \
|
||||
[__syncLock__ release]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __GSWeb_GSWDefines_h__ */
|
||||
|
||||
|
|
42
GSWeb.framework/GSWHTTPIO.h
Normal file
42
GSWeb.framework/GSWHTTPIO.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/** GSWHTTPIO.h - GSWeb: Class GSWHTTPIO
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: David Wetzel <dave@turbocat.de>
|
||||
Date: 12.11.2007
|
||||
|
||||
This file is part of the GNUstep Web Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**/
|
||||
|
||||
#ifndef _GSWHTTPIO_h__
|
||||
#define _GSWHTTPIO_h__
|
||||
#import <Foundation/NSObject.h>
|
||||
#include "GSWWOCompatibility.h"
|
||||
|
||||
@class NSFileHandle;
|
||||
@class GSWRequest;
|
||||
|
||||
|
||||
@interface GSWHTTPIO : NSObject {
|
||||
|
||||
}
|
||||
|
||||
+ (GSWRequest*) readRequestFromFromHandle:(NSFileHandle*) fh;
|
||||
|
||||
@end
|
||||
|
||||
#endif // _GSWHTTPIO_h__
|
374
GSWeb.framework/GSWHTTPIO.m
Normal file
374
GSWeb.framework/GSWHTTPIO.m
Normal file
|
@ -0,0 +1,374 @@
|
|||
/** GSWHTTPIO.m - GSWeb: Class GSWHTTPIO
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: David Wetzel <dave@turbocat.de>
|
||||
Date: 12.11.2007
|
||||
|
||||
This file is part of the GNUstep Web Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
**/
|
||||
|
||||
#include "GSWHTTPIO.h"
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSFileHandle.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <GNUstepBase/GSFileHandle.h>
|
||||
#include <Foundation/NSError.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSDictionary.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "GSWDefines.h"
|
||||
#include "GSWConstants.h"
|
||||
#include "GSWUtils.h"
|
||||
#include "GSWDebug.h"
|
||||
|
||||
#include "GSWMessage.h"
|
||||
#include "GSWResponse.h"
|
||||
#include "GSWRequest.h"
|
||||
|
||||
#define READ_SIZE 1024
|
||||
|
||||
static NSString *URIResponseString = @" GNUstep Web\r\n";
|
||||
static NSString *CONTENT_LENGTH = @"content-length";
|
||||
static NSString *CONTENT_LENGTHCOLON = @"content-length: ";
|
||||
static NSString *GET = @"GET";
|
||||
static NSString *POST = @"POST";
|
||||
static NSString *HEAD = @"HEAD";
|
||||
static NSString *SPACE = @" ";
|
||||
static NSString *HEADERSEP = @": ";
|
||||
static NSString *NEWLINE = @"\r\n";
|
||||
static NSString *NEWLINE2 = @"\r\n";
|
||||
static NSString *HTTP11 = @"HTTP/1.1";
|
||||
static NSString *CONNECTION = @"connection";
|
||||
static NSString *KEEP_ALIVE = @"keep-alive";
|
||||
static NSString *CLOSE = @"close";
|
||||
|
||||
|
||||
/* Get error information.
|
||||
*/
|
||||
@interface NSError (GSCategories)
|
||||
+ (NSError*) _last;
|
||||
@end
|
||||
|
||||
@interface NSFileHandle (GSWFileHandleExtensions)
|
||||
|
||||
- (NSData*) readDataLine;
|
||||
@end
|
||||
|
||||
@implementation NSFileHandle (GSWFileHandleExtensions)
|
||||
|
||||
- (NSData*) readDataLine
|
||||
{
|
||||
NSMutableData *d;
|
||||
int got;
|
||||
char buf[READ_SIZE];
|
||||
|
||||
d = [NSMutableData dataWithCapacity: READ_SIZE];
|
||||
do {
|
||||
//got = [(GSFileHandle*) self read: buf length: 1];
|
||||
got = [(GSFileHandle*) self read: buf length: 1];
|
||||
if (got > 0) {
|
||||
if (buf[0] != 0xd) { // CR
|
||||
if (buf[0] == 0xa) { // NL
|
||||
return d;
|
||||
}
|
||||
[d appendBytes: buf length: got];
|
||||
}
|
||||
} else if (got < 0) {
|
||||
[NSException raise: NSFileHandleOperationException
|
||||
format: @"unable to read from descriptor - %@",
|
||||
[NSError _last]];
|
||||
}
|
||||
} while (got > 0);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation GSWHTTPIO
|
||||
|
||||
|
||||
// PRIVATE
|
||||
void _unpackHeaderLineAddToDict(NSString *line, NSMutableDictionary* headers)
|
||||
{
|
||||
NSArray * components = [line componentsSeparatedByString:HEADERSEP];
|
||||
NSString * value = nil;
|
||||
NSArray * newValue = nil;
|
||||
NSString * key = nil;
|
||||
NSArray * prevValue = nil;
|
||||
|
||||
if ((components) && ([components count] == 2)) {
|
||||
value = [components objectAtIndex:1];
|
||||
key = [components objectAtIndex:0];
|
||||
key = [[key stringByTrimmingSpaces] lowercaseString];
|
||||
|
||||
if ([key isEqualToString:GSWHTTPHeader_AdaptorVersion[GSWNAMES_INDEX]]
|
||||
|| [key isEqualToString:GSWHTTPHeader_ServerName[GSWNAMES_INDEX]]) {
|
||||
// _requestNamingConv=GSWNAMES_INDEX;
|
||||
goto keyDone;
|
||||
}
|
||||
if ([key isEqualToString:GSWHTTPHeader_AdaptorVersion[WONAMES_INDEX]]
|
||||
|| [key isEqualToString:GSWHTTPHeader_ServerName[WONAMES_INDEX]]) {
|
||||
// _requestNamingConv=WONAMES_INDEX;
|
||||
goto keyDone;
|
||||
}
|
||||
|
||||
keyDone:
|
||||
|
||||
prevValue=[headers objectForKey:key];
|
||||
if (prevValue) {
|
||||
newValue=[prevValue arrayByAddingObject:value];
|
||||
} else {
|
||||
newValue=[NSArray arrayWithObject:value];
|
||||
}
|
||||
|
||||
[headers setObject: newValue
|
||||
forKey: key];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//PRIVATE
|
||||
|
||||
void _appendMessageHeaders(GSWMessage * message,NSMutableString * headers)
|
||||
{
|
||||
NSMutableDictionary * headerDict = [message headers];
|
||||
NSArray * keyArray = nil;
|
||||
int i = 0;
|
||||
|
||||
if (headerDict != nil) {
|
||||
int count = 0;
|
||||
if (![headerDict isKindOfClass:[NSMutableDictionary class]]) {
|
||||
headerDict = [[headerDict mutableCopy] autorelease];
|
||||
}
|
||||
[headerDict removeObjectForKey:CONTENT_LENGTH];
|
||||
keyArray = [headerDict allKeys];
|
||||
count = [keyArray count];
|
||||
|
||||
for (; i < count; i++) {
|
||||
NSString * currentKey = [keyArray objectAtIndex:i];
|
||||
NSArray * currentValueArray = [headerDict objectForKey:currentKey];
|
||||
if ([currentValueArray isKindOfClass:[NSArray class]]) {
|
||||
int x = 0;
|
||||
int valueCount = [currentValueArray count];
|
||||
for (; x < valueCount; x++) {
|
||||
[headers appendString:currentKey];
|
||||
[headers appendString:HEADERSEP];
|
||||
[headers appendString:[currentValueArray objectAtIndex:x]];
|
||||
[headers appendString:NEWLINE];
|
||||
}
|
||||
} else {
|
||||
NSString * myStrValue = (NSString*) currentValueArray;
|
||||
[headers appendString:currentKey];
|
||||
[headers appendString:HEADERSEP];
|
||||
[headers appendString:myStrValue];
|
||||
[headers appendString:NEWLINE];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//PRIVATE
|
||||
void _sendMessage(GSWMessage * message, NSFileHandle* fh, NSString * httpVersion, GSWRequest * request, NSMutableString * headers)
|
||||
{
|
||||
int contentLength = 0;
|
||||
BOOL keepAlive = NO;
|
||||
BOOL requestIsHead = NO;
|
||||
|
||||
if (message) {
|
||||
contentLength = [message _contentLength];
|
||||
}
|
||||
|
||||
if (request) {
|
||||
NSString * connectionValue = [request headerForKey:CONNECTION];
|
||||
if (connectionValue) {
|
||||
keepAlive = [connectionValue isEqualToString:KEEP_ALIVE];
|
||||
}
|
||||
requestIsHead = [[request method] isEqualToString:HEAD];
|
||||
}
|
||||
|
||||
_appendMessageHeaders(message,headers);
|
||||
|
||||
if ([httpVersion isEqualToString:HTTP11]) {
|
||||
if (keepAlive == NO) {
|
||||
[headers appendString:@"connection: close\r\n"];
|
||||
} else {
|
||||
[headers appendString:@"connection: keep-alive\r\n"];
|
||||
}
|
||||
}
|
||||
|
||||
if (contentLength > 0) {
|
||||
[headers appendString:CONTENT_LENGTHCOLON];
|
||||
[headers appendString:[NSString stringWithFormat:@"%d\r\n", contentLength]];
|
||||
}
|
||||
[headers appendString:NEWLINE2];
|
||||
|
||||
[fh writeData: [headers dataUsingEncoding:NSISOLatin1StringEncoding
|
||||
allowLossyConversion:YES]];
|
||||
|
||||
if ((requestIsHead == NO) && (contentLength > 0)) {
|
||||
[fh writeData: [message content]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (NSDictionary*) readHeadersFromHandle:(NSFileHandle*) fh
|
||||
{
|
||||
BOOL headersDone=NO;
|
||||
NSArray *lines = [NSMutableArray array];
|
||||
NSData *currentLineData = nil;
|
||||
unsigned int length = 0;
|
||||
NSMutableDictionary *headers = [NSMutableDictionary dictionary];
|
||||
NSString * tmpString = nil;
|
||||
|
||||
NS_DURING {
|
||||
while (YES) {
|
||||
currentLineData = [fh readDataLine];
|
||||
length = [currentLineData length];
|
||||
if (length == 0) {
|
||||
break;
|
||||
}
|
||||
tmpString=[[NSString alloc] initWithData: currentLineData
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
_unpackHeaderLineAddToDict(tmpString,headers);
|
||||
|
||||
[tmpString release]; tmpString = nil;
|
||||
}
|
||||
} NS_HANDLER {
|
||||
NSLog(@"%s -- %@",__PRETTY_FUNCTION__, localException);
|
||||
if (tmpString != nil) {
|
||||
[tmpString release]; tmpString = nil;
|
||||
}
|
||||
headers = nil;
|
||||
} NS_ENDHANDLER;
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
// GET /infotext.html HTTP/1.1
|
||||
// Host: www.example.net
|
||||
+ (NSArray*) readRequestLineFromHandle:(NSFileHandle*) fh
|
||||
{
|
||||
NSString * tmpString = nil;
|
||||
NSArray * components = nil;
|
||||
NSData * currentLineData = nil;
|
||||
int length = 0;
|
||||
|
||||
NS_DURING {
|
||||
currentLineData = [fh readDataLine];
|
||||
length = [currentLineData length];
|
||||
|
||||
if (length > 0) {
|
||||
tmpString=[[NSString alloc] initWithData: currentLineData
|
||||
encoding:NSASCIIStringEncoding];
|
||||
|
||||
components = [tmpString componentsSeparatedByString:@" "];
|
||||
|
||||
[tmpString release]; tmpString = nil;
|
||||
}
|
||||
} NS_HANDLER {
|
||||
NSLog(@"%s -- %@",__PRETTY_FUNCTION__, localException);
|
||||
if (tmpString != nil) {
|
||||
[tmpString release]; tmpString = nil;
|
||||
}
|
||||
components = nil;
|
||||
} NS_ENDHANDLER;
|
||||
return components;
|
||||
}
|
||||
|
||||
+ (NSData*) readContentFromFromHandle: fh
|
||||
method: (NSString *) method
|
||||
length: (int) length
|
||||
{
|
||||
NSData* data = nil;
|
||||
|
||||
if ((([method isEqualToString:GET]) || ([method isEqualToString:HEAD])) ||
|
||||
([method isEqualToString:POST] == NO || (length <1))) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
data = [fh readDataOfLength: length];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
+ (GSWRequest*) readRequestFromFromHandle:(NSFileHandle*) fh
|
||||
{
|
||||
NSDictionary * headers;
|
||||
NSArray * requestArray;
|
||||
int contentLength = 0;
|
||||
NSArray * tmpValue = nil;
|
||||
NSString * method = nil;
|
||||
NSData * contentData = nil;
|
||||
GSWRequest * request = nil;
|
||||
|
||||
[fh setNonBlocking: NO];
|
||||
|
||||
requestArray = [self readRequestLineFromHandle:fh];
|
||||
if ((!requestArray) || ([requestArray count] <3)) {
|
||||
return nil;
|
||||
}
|
||||
headers = [self readHeadersFromHandle:fh];
|
||||
if (!headers) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
method = [requestArray objectAtIndex:0];
|
||||
|
||||
if ((tmpValue = [headers objectForKey:CONTENT_LENGTH]) && ([tmpValue count])) {
|
||||
NSString * tmpString = [tmpValue objectAtIndex:0];
|
||||
|
||||
contentLength = [tmpString intValue];
|
||||
contentData = [self readContentFromFromHandle: fh
|
||||
method: [requestArray objectAtIndex:0]
|
||||
length: contentLength];
|
||||
}
|
||||
|
||||
request = [[GSWRequest alloc] initWithMethod:method
|
||||
uri:[requestArray objectAtIndex:1]
|
||||
httpVersion:[requestArray objectAtIndex:2]
|
||||
headers:headers
|
||||
content:contentData
|
||||
userInfo:nil];
|
||||
|
||||
return [request autorelease];
|
||||
}
|
||||
|
||||
+ (void) sendResponse:(GSWResponse*) response
|
||||
toHandle:(NSFileHandle*) fh
|
||||
request:(GSWRequest*) request
|
||||
{
|
||||
NSString * httpVersion = [response httpVersion];
|
||||
NSMutableString * bufferStr = [NSMutableString string];
|
||||
|
||||
[bufferStr appendString:httpVersion];
|
||||
[bufferStr appendString:SPACE];
|
||||
[bufferStr appendString:GSWIntToNSString([response status])];
|
||||
[bufferStr appendString:URIResponseString];
|
||||
|
||||
_sendMessage(response, fh, httpVersion, request, bufferStr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@end
|
|
@ -32,6 +32,9 @@
|
|||
#ifndef _GSWMessage_h__
|
||||
#define _GSWMessage_h__
|
||||
|
||||
@class GSWMessage;
|
||||
@class GSWCookie;
|
||||
|
||||
typedef struct _GSWMessageIMPs
|
||||
{
|
||||
// Instance IMPs
|
||||
|
@ -171,7 +174,6 @@ GSWEB_EXPORT NSString* GSWMessage_stringByConvertingToHTML(GSWMessage* aMessage,
|
|||
|
||||
//====================================================================
|
||||
@interface GSWMessage (Cookies)
|
||||
-(void)_finalizeCookiesInContext:(GSWContext*)aContext;
|
||||
-(NSMutableArray*)_initCookies;
|
||||
-(NSString*)_formattedCookiesString;
|
||||
-(void)addCookie:(GSWCookie*)cookie;
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
#ifndef _GSWRequest_h__
|
||||
#define _GSWRequest_h__
|
||||
|
||||
@class GSWDynamicURLString;
|
||||
@class GSWContext;
|
||||
|
||||
#include "GSWMessage.h"
|
||||
|
||||
//====================================================================
|
||||
/** A class to handle value and quality like for Accept-Language or
|
||||
|
|
|
@ -199,57 +199,47 @@ RCS_ID("$Id$")
|
|||
content:(NSData*)content
|
||||
userInfo:(NSDictionary*)userInfo
|
||||
{
|
||||
if ((self=[super init]))
|
||||
{
|
||||
if ((self=[super init])) {
|
||||
NSString* adaptorVersion = nil;
|
||||
|
||||
if ((!aMethod) || ([aMethod length]==0))
|
||||
{
|
||||
ExceptionRaise(@"GSRequest",@"Empty/Null method during initialization");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((! anURL) || ([anURL length]==0))
|
||||
{
|
||||
ExceptionRaise(@"GSRequest",@"Empty/Null uri during initialization");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((! aVersion) || ([aVersion length]==0))
|
||||
{
|
||||
ExceptionRaise(@"GSRequest",@"Empty/Null http version during initialization");
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIGNCOPY(_method,aMethod);
|
||||
|
||||
[self setHTTPVersion:aVersion];
|
||||
if ((!aMethod) || ([aMethod length]==0)) {
|
||||
ExceptionRaise(@"GSWRequest",@"Empty/Null method during initialization");
|
||||
}
|
||||
|
||||
[self setHeaders:headers];
|
||||
|
||||
_defaultFormValueEncoding=[[self class]defaultEncoding];
|
||||
|
||||
_applicationNumber=-9999;
|
||||
{
|
||||
NSString* adaptorVersion=[self headerForKey:GSWHTTPHeader_AdaptorVersion[GSWebNamingConv]];
|
||||
if (!adaptorVersion)
|
||||
adaptorVersion=[self headerForKey:GSWHTTPHeader_AdaptorVersion[GSWebNamingConvInversed]];
|
||||
[self _setIsUsingWebServer:(adaptorVersion!=nil)];
|
||||
};
|
||||
_uri = [[GSWDynamicURLString alloc]initWithString:anURL];
|
||||
[_uri checkURL];
|
||||
if (([aMethod isEqualToString:@"GET"] == NO) && ([aMethod isEqualToString:@"POST"] == NO) &&
|
||||
([aMethod isEqualToString:@"HEAD"] == NO)) {
|
||||
|
||||
if (!content)
|
||||
content = [NSData data];
|
||||
// if ([content isKindOfClass:[GSWInputStreamData class]])
|
||||
[self setContent:content];
|
||||
// else
|
||||
// [self appendContentData:content];
|
||||
ExceptionRaise(@"GSWRequest", @"Method '%@' is not supported. To support '%@', you will have to implement a subclass of GSWRequest, and force GSWeb to instantiate it.", aMethod, aMethod);
|
||||
}
|
||||
|
||||
[self setUserInfo:userInfo];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
if ((! anURL) /*|| ([anURL length]==0)*/) {
|
||||
ExceptionRaise(@"GSWRequest",@"Empty/Null uri during initialization");
|
||||
}
|
||||
if ((! aVersion) || ([aVersion length]==0)) {
|
||||
ExceptionRaise(@"GSWRequest",@"Empty/Null http version during initialization");
|
||||
}
|
||||
|
||||
ASSIGNCOPY(_method,aMethod);
|
||||
[self setHTTPVersion:aVersion];
|
||||
[self setHeaders:headers];
|
||||
|
||||
_defaultFormValueEncoding=[[self class] defaultEncoding];
|
||||
_applicationNumber=-9999;
|
||||
adaptorVersion=[self headerForKey:GSWHTTPHeader_AdaptorVersion[GSWebNamingConv]];
|
||||
if (!adaptorVersion) {
|
||||
adaptorVersion=[self headerForKey:GSWHTTPHeader_AdaptorVersion[GSWebNamingConvInversed]];
|
||||
}
|
||||
[self _setIsUsingWebServer:(adaptorVersion!=nil)];
|
||||
|
||||
_uri = [[GSWDynamicURLString alloc] initWithString:anURL];
|
||||
[_uri checkURL];
|
||||
|
||||
if (!content)
|
||||
content = [NSData data];
|
||||
[self setContent:content];
|
||||
|
||||
[self setUserInfo:userInfo];
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
|
|
|
@ -32,23 +32,18 @@
|
|||
#ifndef _GSWRequestHandler_h__
|
||||
#define _GSWRequestHandler_h__
|
||||
|
||||
#define DidHandleRequestNotification "WORequestHandlerDidHandleRequestNotification"
|
||||
|
||||
|
||||
//====================================================================
|
||||
@interface GSWRequestHandler : NSObject <NSLocking>
|
||||
{
|
||||
NSRecursiveLock* _selfLock;
|
||||
#ifndef NDEBUG
|
||||
int _selfLockn;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
-(GSWResponse*)handleRequest:(GSWRequest*)aRequest;
|
||||
-(void)lock;
|
||||
-(void)unlock;
|
||||
|
||||
@end
|
||||
|
||||
//====================================================================
|
||||
@interface GSWRequestHandler (GSWRequestHandlerClassA)
|
||||
+(id)handler;
|
||||
@end
|
||||
#endif //_GSWRequestHandler_h__
|
||||
|
|
|
@ -40,29 +40,25 @@ RCS_ID("$Id$")
|
|||
-(GSWResponse*)handleRequest:(GSWRequest*)aRequest
|
||||
{
|
||||
return [self subclassResponsibility:_cmd];
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)lock
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
-(void)unlock
|
||||
{
|
||||
LOGObjectFnNotImplemented(); //TODOFN
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//====================================================================
|
||||
@implementation GSWRequestHandler (GSWRequestHandlerClassA)
|
||||
+(id)handler
|
||||
{
|
||||
[self subclassResponsibility:_cmd];
|
||||
return nil;
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
#ifndef _GSWResponse_h__
|
||||
#define _GSWResponse_h__
|
||||
|
||||
@class GSWResponse;
|
||||
@class GSWContext;
|
||||
@class GSWRequest;
|
||||
|
||||
typedef struct _GSWResponseIMPs
|
||||
{
|
||||
// Instance IMPs
|
||||
|
|
|
@ -69,7 +69,6 @@
|
|||
#define GSWComponentRequestHandler WOComponentRequestHandler
|
||||
#define GSWResourceRequestHandler WOResourceRequestHandler
|
||||
#define GSWDirectActionRequestHandler WODirectActionRequestHandler
|
||||
#define GSWDefaultAdaptorThread WODefaultAdaptorThread
|
||||
#define GSWKeyValueAssociation WOKeyValueAssociation
|
||||
#define GSWConstantValueAssociation WOConstantValueAssociation
|
||||
#define GSWHTMLStaticElement WOHTMLStaticElement
|
||||
|
|
87
GSWeb.framework/GSWWorkerThread.h
Executable file
87
GSWeb.framework/GSWWorkerThread.h
Executable file
|
@ -0,0 +1,87 @@
|
|||
/** Implementation GSWWorkerThread for GNUStep
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: David Wetzel <dave@turbocat.de>
|
||||
Date: 2007
|
||||
|
||||
This file is part of the GNUstep Web Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
// $Id: GSWToggle.h 14202 2002-07-27 23:48:47Z mguesdon $
|
||||
|
||||
#ifndef _GSWWorkerThread_h__
|
||||
#define _GSWWorkerThread_h__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#include "GSWWOCompatibility.h"
|
||||
|
||||
|
||||
@class GSWApplication;
|
||||
@class GSWDefaultAdaptor;
|
||||
@class NSRunLoop;
|
||||
@class NSFileHandle;
|
||||
@class NSThread;
|
||||
@class NSAutoreleasePool;
|
||||
@class GSWAdaptor;
|
||||
|
||||
@interface GSWWorkerThread: NSObject
|
||||
{
|
||||
GSWApplication *_app;
|
||||
GSWDefaultAdaptor *_mtAdaptor; // 4.5
|
||||
NSRunLoop *_currentRunLoop; // 4.5
|
||||
NSFileHandle * _serverSocket; // rename to _serverFileHandle
|
||||
// called int _currentSocket in 4.5
|
||||
NSFileHandle *_currentSocket; // rename to _currentFileHandle
|
||||
NSThread * _t;
|
||||
NSAutoreleasePool * _pool;
|
||||
BOOL _keepAlive; // 4.5
|
||||
int _maxSocketIdleTime;
|
||||
BOOL _errorOnRead;
|
||||
BOOL _dispatchError;
|
||||
BOOL _runFlag;
|
||||
BOOL _processingRequest;
|
||||
BOOL _restricted;
|
||||
long _expTime;
|
||||
int _reqCount;
|
||||
BOOL _logOnce;
|
||||
BOOL _isMultiThreadEnabled; // gsw only
|
||||
|
||||
// verified in 4.5:
|
||||
// id _selfId;
|
||||
// WODefaultAdaptor *_mtAdaptor;
|
||||
// NSRunLoop *_currentRunLoop;
|
||||
// int _currentSocket;
|
||||
// id _inputBuffer;
|
||||
// int _inputBufferLength;
|
||||
// int _inputBufferIndex;
|
||||
// BOOL _keepAlive;
|
||||
// BOOL _errorOnRead;
|
||||
// BOOL _runFlag;
|
||||
}
|
||||
|
||||
-(id)initWithApp:(GSWApplication*)application
|
||||
adaptor:(GSWAdaptor*)adaptor
|
||||
stream:(NSFileHandle*)stream;
|
||||
|
||||
-(void)runOnce;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif // _GSWWorkerThread_h__
|
||||
|
236
GSWeb.framework/GSWWorkerThread.m
Executable file
236
GSWeb.framework/GSWWorkerThread.m
Executable file
|
@ -0,0 +1,236 @@
|
|||
/** Implementation GSWWorkerThread for GNUStep
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
Written by: David Wetzel <dave@turbocat.de>
|
||||
Date: 1997
|
||||
|
||||
This file is part of the GNUstep Web Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <Foundation/NSThread.h>
|
||||
|
||||
#include "GSWWOCompatibility.h"
|
||||
|
||||
#include "GSWWorkerThread.h"
|
||||
|
||||
|
||||
#include "GSWDefines.h"
|
||||
#include "GSWConstants.h"
|
||||
#include "GSWUtils.h"
|
||||
#include "GSWDebug.h"
|
||||
|
||||
#include "GSWRequest.h"
|
||||
#include "GSWApplication.h"
|
||||
#include "GSWAdaptor.h"
|
||||
#include "GSWDefaultAdaptor.h"
|
||||
#include "GSWResponse.h"
|
||||
#include "GSWHTTPIO.h"
|
||||
|
||||
static NSData* lineFeedData=nil;
|
||||
static NSString *REQUEST_ID = @"x-webobjects-request-id";
|
||||
|
||||
@interface NSThread (WeKnowWhatWeDo)
|
||||
- (void)run;
|
||||
|
||||
@end
|
||||
@implementation GSWWorkerThread
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [GSWWorkerThread class])
|
||||
{
|
||||
// ASSIGN(lineFeedData,([[NSString stringWithString:@"\n"] dataUsingEncoding:NSASCIIStringEncoding]));
|
||||
}
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
// TODO: add vars!
|
||||
|
||||
DESTROY(_serverSocket);
|
||||
DESTROY(_currentSocket);
|
||||
|
||||
// NSThread * _t;
|
||||
|
||||
_app = nil;
|
||||
_mtAdaptor = nil;
|
||||
DESTROY(_pool);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
-(id)initWithApp:(GSWApplication*)application
|
||||
adaptor:(GSWAdaptor*)adaptor
|
||||
stream:(NSFileHandle*)stream
|
||||
{
|
||||
if ((self = [self init])) {
|
||||
_app = application;
|
||||
_mtAdaptor = (GSWDefaultAdaptor*)adaptor;
|
||||
ASSIGN(_serverSocket,stream);
|
||||
_keepAlive=NO;
|
||||
_maxSocketIdleTime=300; // 300 ms
|
||||
_isMultiThreadEnabled = [adaptor isMultiThreadEnabled];
|
||||
|
||||
if (_isMultiThreadEnabled) {
|
||||
_t = [[NSThread alloc] initWithTarget:self
|
||||
selector:@selector(runOnce)
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector:@selector(threadWillExit:)
|
||||
name:NSThreadWillExitNotification
|
||||
object: _t];
|
||||
_runFlag = YES;
|
||||
[_t start];
|
||||
} else {
|
||||
_runFlag = YES;
|
||||
[self runOnce];
|
||||
}
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)threadWillExit:(NSNotification*)notification
|
||||
{
|
||||
NSLog(@"%s",__PRETTY_FUNCTION__);
|
||||
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
||||
|
||||
[_mtAdaptor workerThreadWillExit:self];
|
||||
}
|
||||
|
||||
//PRIVATE!
|
||||
- (void) _closeSocket
|
||||
{
|
||||
if (_currentSocket == nil) {
|
||||
return;
|
||||
}
|
||||
[_currentSocket closeFile];
|
||||
_currentSocket = nil;
|
||||
}
|
||||
|
||||
-(void)runOnce
|
||||
{
|
||||
GSWRequest *request = nil;
|
||||
BOOL ok = NO;
|
||||
struct timeval timeout;
|
||||
GSWResponse *response;
|
||||
|
||||
if ((!_runFlag) || (_serverSocket == nil)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
_errorOnRead = NO;
|
||||
// _maxSocketIdleTime is milisecs!
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = _maxSocketIdleTime * 1000;
|
||||
|
||||
NS_DURING {
|
||||
setsockopt([_serverSocket fileDescriptor], SOL_SOCKET, SO_RCVTIMEO, &timeout,sizeof(timeout));
|
||||
|
||||
request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
|
||||
} NS_HANDLER {
|
||||
_errorOnRead = YES;
|
||||
NSLog(@"%s -- dropping connection reason: %@",__PRETTY_FUNCTION__, [localException reason]);
|
||||
} NS_ENDHANDLER;
|
||||
|
||||
// "womp" is the request handler key used by the WOTaskD contacing your app
|
||||
if ((_errorOnRead || (request == nil)) ||
|
||||
((([[_app class] isDirectConnectEnabled] == NO) && ([request isUsingWebServer] == NO)) &&
|
||||
([@"womp" isEqual:[request requestHandlerKey]] == NO))) {
|
||||
goto done;
|
||||
}
|
||||
_processingRequest = YES;
|
||||
_dispatchError = NO;
|
||||
|
||||
NS_DURING {
|
||||
response = [_app dispatchRequest:request];
|
||||
} NS_HANDLER {
|
||||
NSLog(@"%s -- Exception occurred while responding to client: %@",
|
||||
__PRETTY_FUNCTION__, [localException description]);
|
||||
_dispatchError = YES;
|
||||
response = [GSWDefaultAdaptor _lastDitchErrorResponse];
|
||||
} NS_ENDHANDLER;
|
||||
|
||||
if (response) {
|
||||
NSString * reqid = [request headerForKey:REQUEST_ID];
|
||||
if (reqid) {
|
||||
[response setHeader:reqid forKey:REQUEST_ID];
|
||||
}
|
||||
NS_DURING {
|
||||
// request = [GSWHTTPIO readRequestFromFromHandle: _serverSocket];
|
||||
ok = [GSWHTTPIO sendResponse:response
|
||||
toHandle: _serverSocket
|
||||
request:request];
|
||||
} NS_HANDLER {
|
||||
NSLog(@"%s -- Exception while sending response: %@",
|
||||
__PRETTY_FUNCTION__, [localException description]);
|
||||
} NS_ENDHANDLER;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
[self _closeSocket];
|
||||
|
||||
_processingRequest = NO;
|
||||
if (_isMultiThreadEnabled) {
|
||||
[NSThread exit];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -[WOWorkerThread runLoopOnce]
|
||||
// -[WOWorkerThread runOnce]
|
||||
// -[WOWorkerThread run]
|
||||
// -[WOWorkerThread stop]
|
||||
// -[WOWorkerThread(WOWkrObjRequestHandling) readLine:withLength:]
|
||||
// -[WOWorkerThread(WOWkrObjRequestHandling) readBlob:withLength:]
|
||||
// -[WOWorkerThread(WOWkrObjRequestHandling) readRequest]
|
||||
// -[WOWorkerThread(WOWkrObjRequestHandling) sendResponse:]
|
||||
|
||||
|
||||
- (NSString*) description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%s %p socket:%@ >",
|
||||
object_get_class_name(self),
|
||||
(void*)self, _serverSocket];
|
||||
}
|
||||
|
||||
@end
|
||||
@implementation GSWWorkerThread (WorkerThreadDepricated)
|
||||
|
||||
-(id)initWithApp:(GSWApplication*)application
|
||||
withAdaptor:(GSWAdaptor*)adaptor
|
||||
withStream:(NSFileHandle*)stream
|
||||
{
|
||||
NSLog(@"%s is depricated use initWithApp:adaptor:stream: instead.",__PRETTY_FUNCTION__);
|
||||
return [self initWithApp: application adaptor:adaptor stream:stream];
|
||||
}
|
||||
|
||||
// this exists in WO 4.5
|
||||
- (id) initWithApp:(GSWApplication*) app andMtAdaptor:(GSWAdaptor*) adaptor restricted:(void*) rst
|
||||
{
|
||||
return [self initWithApp:app adaptor:adaptor stream:rst];
|
||||
}
|
||||
|
||||
@end
|
|
@ -111,7 +111,6 @@
|
|||
@class GSWStaticResourceRequestHandler;
|
||||
@class GSWActionRequestHandler;
|
||||
@class GSWDirectActionRequestHandler;
|
||||
@class GSWDefaultAdaptorThread;
|
||||
@class GSWKeyValueAssociation;
|
||||
@class GSWConstantValueAssociation;
|
||||
@class GSWHTMLStaticElement;
|
||||
|
@ -235,7 +234,6 @@
|
|||
#include "GSWStaticResourceRequestHandler.h"
|
||||
#include "GSWActionRequestHandler.h"
|
||||
#include "GSWDirectActionRequestHandler.h"
|
||||
#include "GSWDefaultAdaptorThread.h"
|
||||
#include "GSWKeyValueAssociation.h"
|
||||
#include "GSWConstantValueAssociation.h"
|
||||
#include "GSWTemplateParser.h"
|
||||
|
|
Loading…
Reference in a new issue