From b35b40f235cd57696c91e3261c98d12fe4a79a08 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Sat, 7 Aug 2004 13:25:19 +0000 Subject: [PATCH] Add session timeouts. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@19835 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 4 +++ WebServer.h | 10 ++++++ WebServer.m | 102 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index fe10712..afe024c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Sat Aug 07 14:25:00 2004 Richard Frith-Macdonald + + * WebServer.m: Add session timeouts to kill off idle sessions. + Tue Jul 27 17:30:00 2004 Richard Frith-Macdonald * configure.ac: Give more help when postgres is not found. diff --git a/WebServer.h b/WebServer.h index 9e240e9..b0e5ee8 100644 --- a/WebServer.h +++ b/WebServer.h @@ -131,6 +131,9 @@ NSMapTable *_sessions; unsigned _handled; NSString *_root; + NSTimer *_ticker; + NSTimeInterval _sessionTimeout; + NSTimeInterval _ticked; } /** @@ -291,6 +294,12 @@ */ - (void) setRoot: (NSString*)aPath; +/** + * Sets the time after which an idle session should be shut down.
+ * Default is 30.0 + */ +- (void) setSessionTimeout: (NSTimeInterval)aDelay; + /** * Sets a flag to determine whether verbose logging is to be performed.
* If this is YES then all incming requests and their responses will @@ -320,6 +329,7 @@ using: (NSDictionary*)map into: (NSMutableString*)result depth: (unsigned)depth; + @end /** diff --git a/WebServer.m b/WebServer.m index fd9efe7..94547da 100644 --- a/WebServer.m +++ b/WebServer.m @@ -28,21 +28,27 @@ @interface WebServerSession : NSObject { - NSString *address; - NSFileHandle *handle; - GSMimeParser *parser; - NSMutableData *buffer; - unsigned byteCount; + NSString *address; + NSFileHandle *handle; + GSMimeParser *parser; + NSMutableData *buffer; + unsigned byteCount; + NSTimeInterval ticked; + BOOL processing; } - (NSString*) address; - (NSMutableData*) buffer; - (NSFileHandle*) handle; - (unsigned) moreBytes: (unsigned)count; - (GSMimeParser*) parser; +- (BOOL) processing; - (void) setAddress: (NSString*)aString; - (void) setBuffer: (NSMutableData*)aBuffer; - (void) setHandle: (NSFileHandle*)aHandle; - (void) setParser: (GSMimeParser*)aParser; +- (void) setProcessing: (BOOL)aFlag; +- (void) setTicked: (NSTimeInterval)when; +- (NSTimeInterval) ticked; @end @implementation WebServerSession @@ -88,6 +94,11 @@ return parser; } +- (BOOL) processing +{ + return processing; +} + - (void) setAddress: (NSString*)aString { ASSIGN(address, aString); @@ -107,6 +118,21 @@ { ASSIGN(parser, aParser); } + +- (void) setProcessing: (BOOL)aFlag +{ + processing = aFlag; +} + +- (void) setTicked: (NSTimeInterval)when +{ + ticked = when; +} + +- (NSTimeInterval) ticked +{ + return ticked; +} @end @interface WebServer (Private) @@ -116,12 +142,18 @@ - (void) _didWrite: (NSNotification*)notification; - (void) _endSession: (WebServerSession*)session; - (void) _process: (WebServerSession*)session; +- (void) _ticker: (NSTimer*)timer; @end @implementation WebServer - (void) dealloc { + if (_ticker != nil) + { + [_ticker invalidate]; + _ticker = nil; + } [self setPort: nil secure: nil]; DESTROY(_nc); DESTROY(_root); @@ -300,12 +332,18 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) - (id) init { _nc = RETAIN([NSNotificationCenter defaultCenter]); + _sessionTimeout = 30.0; _maxSess = 32; _maxBodySize = 8*1024; _maxRequestSize = 4*1024*1024; _substitutionLimit = 4; _sessions = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSObjectMapValueCallBacks, 0); + _ticker = [NSTimer scheduledTimerWithTimeInterval: 0.8 + target: self + selector: @selector(_timeout:) + userInfo: 0 + repeats: YES]; return self; } @@ -597,6 +635,11 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) ASSIGN(_root, aPath); } +- (void) setSessionTimeout: (NSTimeInterval)aDelay +{ + _sessionTimeout = aDelay; +} + - (void) setSubstitutionLimit: (unsigned)depth { _substitutionLimit = depth; @@ -838,6 +881,9 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) } // NSLog(@"Data read on %@ ... %@", session, d); + // Mark session as having had I/O ... not idle. + [session setTicked: _ticked]; + if (parser == nil) { unsigned char *bytes; @@ -1082,7 +1128,7 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) - (void) _process: (WebServerSession*)session { - GSMimeDocument *request = [[session parser] mimeDocument]; + GSMimeDocument *request; GSMimeDocument *response; BOOL responded = NO; NSMutableData *raw; @@ -1094,6 +1140,8 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) NSEnumerator *enumerator; GSMimeHeader *hdr; + AUTORELEASE(RETAIN(session)); + request = [[session parser] mimeDocument]; response = AUTORELEASE([GSMimeDocument new]); [response setContent: [NSData data] type: @"text/plain" name: nil]; [request setHeader: @"x-remote-address" @@ -1103,12 +1151,18 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) if (_verbose == YES) NSLog(@"Request %@ - %@", session, request); NS_DURING { + [session setProcessing: YES]; + [session setTicked: _ticked]; responded = [_delegate processRequest: request response: response for: self]; + _ticked = [NSDate timeIntervalSinceReferenceDate]; + [session setTicked: _ticked]; + [session setProcessing: NO]; } NS_HANDLER { + [session setProcessing: NO]; [self _alert: @"Exception %@, processing %@", localException, request]; [response setHeader: @"http" value: @"HTTP/1.0 500 Internal Server Error" @@ -1190,5 +1244,41 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf) if (_verbose == YES) NSLog(@"Response %@ - %@", session, out); [[session handle] writeInBackgroundAndNotify: out]; } + +- (void) _ticker: (NSTimer*)timer +{ + unsigned count; + + _ticked = [NSDate timeIntervalSinceReferenceDate]; + + count = NSCountMapTable(_sessions); + if (count > 0) + { + NSMapEnumerator enumerator; + WebServerSession *session; + NSFileHandle *handle; + NSMutableArray *array; + + array = [NSMutableArray arrayWithCapacity: count]; + enumerator = NSEnumerateMapTable(_sessions); + while (NSNextMapEnumeratorPair(&enumerator, + (void **)(&handle), (void**)(&session))) + { + if (_ticked - [session ticked] > _sessionTimeout + && [session processing] == NO) + { + [array addObject: session]; + } + } + NSEndMapTableEnumeration(&enumerator); + while ([array count] > 0) + { + session = [array objectAtIndex: 0]; + [self _alert: @"Session timed out - %@", session]; + [self _endSession: session]; + [array removeObjectAtIndex: 0]; + } + } +} @end