mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-05-13 00:02:02 +08:00
Added connected state to GCDWebServer
This commit is contained in:
@@ -48,6 +48,8 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r
|
||||
@protocol GCDWebServerDelegate <NSObject>
|
||||
@optional
|
||||
- (void)webServerDidStart:(GCDWebServer*)server;
|
||||
- (void)webServerDidConnect:(GCDWebServer*)server;
|
||||
- (void)webServerDidDisconnect:(GCDWebServer*)server;
|
||||
- (void)webServerDidStop:(GCDWebServer*)server;
|
||||
@end
|
||||
|
||||
@@ -56,6 +58,7 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r
|
||||
@property(nonatomic, readonly, getter=isRunning) BOOL running;
|
||||
@property(nonatomic, readonly) NSUInteger port;
|
||||
@property(nonatomic, readonly) NSString* bonjourName; // Only non-nil if Bonjour registration is active
|
||||
@property(nonatomic, readonly, getter=isConnected) BOOL connected;
|
||||
- (instancetype)init;
|
||||
- (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock;
|
||||
- (void)removeAllHandlers;
|
||||
@@ -70,6 +73,7 @@ typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* r
|
||||
+ (Class)connectionClass; // Default is GCDWebServerConnection
|
||||
+ (NSString*)serverName; // Default is class name
|
||||
+ (BOOL)shouldAutomaticallyMapHEADToGET; // Default is YES which means HEAD requests are mapped to GET requests with the response body being discarded
|
||||
+ (NSTimeInterval)connectedStateCoalescingInterval; // Allows coalescing of fast sequences of -webServerDidConnect: / -webServerDidDisconnect: - Default is 1.0 seconds (set to 0.0 to disable)
|
||||
@end
|
||||
|
||||
@interface GCDWebServer (Extensions)
|
||||
|
||||
@@ -44,7 +44,11 @@
|
||||
@interface GCDWebServer () {
|
||||
@private
|
||||
id<GCDWebServerDelegate> __unsafe_unretained _delegate;
|
||||
dispatch_queue_t _syncQueue;
|
||||
NSMutableArray* _handlers;
|
||||
NSInteger _activeConnections; // Accessed only with _syncQueue
|
||||
BOOL _connected;
|
||||
CFRunLoopTimerRef _connectedTimer;
|
||||
|
||||
NSUInteger _port;
|
||||
dispatch_source_t _source;
|
||||
@@ -120,7 +124,7 @@ static void _SignalHandler(int signal) {
|
||||
|
||||
@implementation GCDWebServer
|
||||
|
||||
@synthesize delegate=_delegate, handlers=_handlers, port=_port;
|
||||
@synthesize delegate=_delegate, handlers=_handlers, port=_port, connected=_connected;
|
||||
|
||||
#ifndef __GCDWEBSERVER_LOGGING_HEADER__
|
||||
|
||||
@@ -137,24 +141,99 @@ static void _SignalHandler(int signal) {
|
||||
GCDWebServerInitializeFunctions();
|
||||
}
|
||||
|
||||
static void _ConnectedTimerCallBack(CFRunLoopTimerRef timer, void* info) {
|
||||
@autoreleasepool {
|
||||
[(ARC_BRIDGE GCDWebServer*)info _didDisconnect];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if ((self = [super init])) {
|
||||
_syncQueue = dispatch_queue_create([NSStringFromClass([self class]) UTF8String], DISPATCH_QUEUE_SERIAL);
|
||||
_handlers = [[NSMutableArray alloc] init];
|
||||
CFRunLoopTimerContext context = {0, (ARC_BRIDGE void*)self, NULL, NULL, NULL};
|
||||
if ([[self class] connectedStateCoalescingInterval] > 0.0) {
|
||||
_connectedTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VAL, HUGE_VAL, 0, 0, _ConnectedTimerCallBack, &context);
|
||||
CFRunLoopAddTimer(CFRunLoopGetMain(), _connectedTimer, kCFRunLoopCommonModes);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
DCHECK(_connected == NO);
|
||||
DCHECK(_activeConnections == 0);
|
||||
|
||||
_delegate = nil;
|
||||
if (_source) {
|
||||
[self stop];
|
||||
}
|
||||
|
||||
if (_connectedTimer) {
|
||||
CFRunLoopTimerInvalidate(_connectedTimer);
|
||||
CFRelease(_connectedTimer);
|
||||
}
|
||||
ARC_RELEASE(_handlers);
|
||||
ARC_DISPATCH_RELEASE(_syncQueue);
|
||||
|
||||
ARC_DEALLOC(super);
|
||||
}
|
||||
|
||||
- (void)_didConnect {
|
||||
DCHECK(_connected == NO);
|
||||
_connected = YES;
|
||||
LOG_DEBUG(@"Did connect");
|
||||
if ([_delegate respondsToSelector:@selector(webServerDidConnect:)]) {
|
||||
[_delegate webServerDidConnect:self];
|
||||
}
|
||||
}
|
||||
|
||||
// Called from any thread
|
||||
- (void)willStartConnection:(GCDWebServerConnection*)connection {
|
||||
dispatch_sync(_syncQueue, ^{
|
||||
|
||||
DCHECK(_activeConnections >= 0);
|
||||
if (_activeConnections == 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (_connectedTimer) {
|
||||
CFRunLoopTimerSetNextFireDate(_connectedTimer, HUGE_VAL);
|
||||
}
|
||||
if (_connected == NO) {
|
||||
[self _didConnect];
|
||||
}
|
||||
});
|
||||
}
|
||||
_activeConnections += 1;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
- (void)_didDisconnect {
|
||||
DCHECK(_connected == YES);
|
||||
_connected = NO;
|
||||
LOG_DEBUG(@"Did disconnect");
|
||||
if ([_delegate respondsToSelector:@selector(webServerDidDisconnect:)]) {
|
||||
[_delegate webServerDidDisconnect:self];
|
||||
}
|
||||
}
|
||||
|
||||
// Called from any thread
|
||||
- (void)didEndConnection:(GCDWebServerConnection*)connection {
|
||||
dispatch_sync(_syncQueue, ^{
|
||||
DCHECK(_activeConnections > 0);
|
||||
_activeConnections -= 1;
|
||||
if (_activeConnections == 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (_connectedTimer) {
|
||||
CFRunLoopTimerSetNextFireDate(_connectedTimer, CFAbsoluteTimeGetCurrent() + [[self class] connectedStateCoalescingInterval]);
|
||||
} else {
|
||||
[self _didDisconnect];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (NSString*)bonjourName {
|
||||
CFStringRef name = _service ? CFNetServiceGetName(_service) : NULL;
|
||||
return name && CFStringGetLength(name) ? ARC_BRIDGE_RELEASE(CFStringCreateCopy(kCFAllocatorDefault, name)) : nil;
|
||||
@@ -346,6 +425,10 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSTimeInterval)connectedStateCoalescingInterval {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GCDWebServer (Extensions)
|
||||
|
||||
@@ -584,6 +584,9 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
_localAddress = ARC_RETAIN(localAddress);
|
||||
_remoteAddress = ARC_RETAIN(remoteAddress);
|
||||
_socket = socket;
|
||||
LOG_DEBUG(@"Did open connection on socket %i", _socket);
|
||||
|
||||
[_server willStartConnection:self];
|
||||
|
||||
if (![self open]) {
|
||||
close(_socket);
|
||||
@@ -592,7 +595,6 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
}
|
||||
_opened = YES;
|
||||
|
||||
LOG_DEBUG(@"Did open connection on socket %i", _socket);
|
||||
[self _readRequestHeaders];
|
||||
}
|
||||
return self;
|
||||
@@ -620,10 +622,6 @@ static NSString* _StringFromAddressData(NSData* data) {
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (_opened) {
|
||||
[self close];
|
||||
}
|
||||
|
||||
int result = close(_socket);
|
||||
if (result != 0) {
|
||||
LOG_ERROR(@"Failed closing socket %i for connection: %s (%i)", _socket, strerror(errno), errno);
|
||||
@@ -631,6 +629,11 @@ static NSString* _StringFromAddressData(NSData* data) {
|
||||
LOG_DEBUG(@"Did close connection on socket %i", _socket);
|
||||
}
|
||||
|
||||
if (_opened) {
|
||||
[self close];
|
||||
}
|
||||
|
||||
[_server didEndConnection:self];
|
||||
ARC_RELEASE(_server);
|
||||
ARC_RELEASE(_localAddress);
|
||||
ARC_RELEASE(_remoteAddress);
|
||||
@@ -783,6 +786,7 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET
|
||||
unlink([_responsePath fileSystemRepresentation]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_request) {
|
||||
LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
|
||||
} else {
|
||||
|
||||
@@ -128,6 +128,8 @@ extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType);
|
||||
|
||||
@interface GCDWebServer ()
|
||||
@property(nonatomic, readonly) NSArray* handlers;
|
||||
- (void)willStartConnection:(GCDWebServerConnection*)connection;
|
||||
- (void)didEndConnection:(GCDWebServerConnection*)connection;
|
||||
@end
|
||||
|
||||
@interface GCDWebServerHandler : NSObject
|
||||
|
||||
+74
@@ -52,6 +52,77 @@ typedef enum {
|
||||
kMode_StreamingResponse
|
||||
} Mode;
|
||||
|
||||
@interface Delegate : NSObject <GCDWebServerDelegate, GCDWebDAVServerDelegate, GCDWebUploaderDelegate>
|
||||
@end
|
||||
|
||||
@implementation Delegate
|
||||
|
||||
- (void)_logDelegateCall:(SEL)selector {
|
||||
fprintf(stdout, "<DELEGATE METHOD \"%s\" CALLED>\n", [NSStringFromSelector(selector) UTF8String]);
|
||||
}
|
||||
|
||||
- (void)webServerDidStart:(GCDWebServer*)server {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webServerDidConnect:(GCDWebServer*)server {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webServerDidDisconnect:(GCDWebServer*)server {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webServerDidStop:(GCDWebServer*)server {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)davServer:(GCDWebDAVServer*)server didDownloadFileAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)davServer:(GCDWebDAVServer*)server didUploadFileAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)davServer:(GCDWebDAVServer*)server didMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)davServer:(GCDWebDAVServer*)server didCopyItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)davServer:(GCDWebDAVServer*)server didDeleteItemAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)davServer:(GCDWebDAVServer*)server didCreateDirectoryAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webUploader:(GCDWebUploader*)uploader didDownloadFileAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webUploader:(GCDWebUploader*)uploader didUploadFileAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webUploader:(GCDWebUploader*)uploader didMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webUploader:(GCDWebUploader*)uploader didDeleteItemAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
- (void)webUploader:(GCDWebUploader*)uploader didCreateDirectoryAtPath:(NSString*)path {
|
||||
[self _logDelegateCall:_cmd];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
int result = -1;
|
||||
@autoreleasepool {
|
||||
@@ -199,6 +270,8 @@ int main(int argc, const char* argv[]) {
|
||||
#endif
|
||||
|
||||
if (webServer) {
|
||||
Delegate* delegate = [[Delegate alloc] init];
|
||||
webServer.delegate = delegate;
|
||||
if (testDirectory) {
|
||||
fprintf(stdout, "<RUNNING TESTS FROM \"%s\">\n\n", [testDirectory UTF8String]);
|
||||
result = (int)[webServer runTestsInDirectory:testDirectory withPort:8080];
|
||||
@@ -214,6 +287,7 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
#if !__has_feature(objc_arc)
|
||||
[webServer release];
|
||||
[delegate release];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user