Limit maximum incoming connections from any one host.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@19929 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2004-08-27 08:35:34 +00:00
parent 1ff795dd26
commit 6df9bca4b9
3 changed files with 40 additions and 14 deletions

View file

@ -1,3 +1,8 @@
Fri Aug 28 09:30:00 2004 Richard Frith-Macdonald <rfm@gnu.org>
* WebServer.[hm]: Add support for limiting maximum number of incoming
sessions permitted from mone host.
Tue Aug 24 14:30:00 2004 Richard Frith-Macdonald <rfm@gnu.org>
* WebServer.[hm]: Add support for HTTP/1.1 persistent connections.

View file

@ -56,6 +56,7 @@
#include <Foundation/NSFileHandle.h>
#include <Foundation/NSNotification.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSTimer.h>
#include <GNUstepBase/GSMime.h>
@ -124,6 +125,7 @@
*/
@interface WebServer : NSObject
{
@private
NSNotificationCenter *_nc;
NSString *_port;
BOOL _accepting;
@ -133,7 +135,8 @@
unsigned int _substitutionLimit;
unsigned int _maxBodySize;
unsigned int _maxRequestSize;
unsigned int _maxSess;
unsigned int _maxSessions;
unsigned int _maxPerHost;
id _delegate;
NSFileHandle *_listener;
NSMapTable *_sessions;
@ -142,6 +145,7 @@
NSTimer *_ticker;
NSTimeInterval _sessionTimeout;
NSTimeInterval _ticked;
NSCountedSet *_perHost;
}
/**
@ -268,10 +272,17 @@
* Sets the maximum number of simultaneous sessions with clients.<br />
* The default is 32.<br />
* A value of zero permits unlimited connections.
* Setting a value greater than 512 is treated as a setting of 512
*/
- (void) setMaxSessions: (unsigned)max;
/**
* Sets the maximum number of simultaneous sessions with a particular
* remote host.<br />
* The default is 8.<br />
* A value of zero permits unlimited connections.
*/
- (void) setMaxSessionsPerHost: (unsigned)max;
/**
* Sets the port and security information for the receiver ... without
* this the receiver will not listen for incoming requests.<br />

View file

@ -179,6 +179,7 @@
DESTROY(_nc);
DESTROY(_root);
DESTROY(_hosts);
DESTROY(_perHost);
if (_sessions != 0)
{
NSFreeMapTable(_sessions);
@ -346,20 +347,22 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
{
return [NSString stringWithFormat:
@"%@ on %@, %u of %u sessions active, %u requests, listening: %@",
[super description], _port, NSCountMapTable(_sessions), _maxSess, _handled,
_accepting == YES ? @"yes" : @"no"];
[super description], _port, NSCountMapTable(_sessions),
_maxSessions, _handled, _accepting == YES ? @"yes" : @"no"];
}
- (id) init
{
_nc = RETAIN([NSNotificationCenter defaultCenter]);
_sessionTimeout = 30.0;
_maxSess = 32;
_maxPerHost = 8;
_maxSessions = 32;
_maxBodySize = 8*1024;
_maxRequestSize = 4*1024*1024;
_substitutionLimit = 4;
_sessions = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
_perHost = [NSMutableSet new];
_ticker = [NSTimer scheduledTimerWithTimeInterval: 0.8
target: self
selector: @selector(_timeout:)
@ -575,11 +578,12 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
- (void) setMaxSessions: (unsigned)max
{
_maxSess = max;
if (_maxSess > 512)
{
_maxSess = 512;
}
_maxSessions = max;
}
- (void) setMaxSessionsPerHost: (unsigned)max
{
_maxPerHost = max;
}
- (BOOL) setPort: (NSString*)aPort secure: (NSDictionary*)secure
@ -639,8 +643,8 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
selector: @selector(_didConnect:)
name: NSFileHandleConnectionAcceptedNotification
object: _listener];
if (_accepting == NO
&& (_maxSess <= 0 || NSCountMapTable(_sessions) < _maxSess))
if (_accepting == NO && (_maxSessions <= 0
|| NSCountMapTable(_sessions) < _maxSessions))
{
[_listener acceptConnectionInBackgroundAndNotify];
_accepting = YES;
@ -823,6 +827,10 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
{
[self _alert: @"Invalid host (%@) on new connection.", a];
}
else if (_maxPerHost > 0 && [_perHost countForObject: a] >= _maxPerHost)
{
[self _alert: @"Too many connections from (%@) for new connect.", a];
}
else if (_sslConfig != nil && [hdl sslAccept] == NO)
{
[self _alert: @"SSL accept fail on new connection (%@).", a];
@ -836,6 +844,7 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
[session setBuffer: [NSMutableData dataWithCapacity: 1024]];
[session setTicked: _ticked];
NSMapInsert(_sessions, (void*)hdl, (void*)session);
[_perHost addObject: [session address]];
RELEASE(session);
[_nc addObserver: self
selector: @selector(_didRead:)
@ -850,7 +859,7 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
}
}
if (_accepting == NO
&& (_maxSess == 0 || NSCountMapTable(_sessions) < _maxSess))
&& (_maxSessions == 0 || NSCountMapTable(_sessions) < _maxSessions))
{
[_listener acceptConnectionInBackgroundAndNotify];
_accepting = YES;
@ -1153,9 +1162,10 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
[_nc removeObserver: self
name: GSFileHandleWriteCompletionNotification
object: hdl];
[_perHost removeObject: [session address]];
NSMapRemove(_sessions, (void*)hdl);
if (_accepting == NO
&& (_maxSess <= 0 || NSCountMapTable(_sessions) < _maxSess))
&& (_maxSessions <= 0 || NSCountMapTable(_sessions) < _maxSessions))
{
[_listener acceptConnectionInBackgroundAndNotify];
_accepting = YES;