Просмотр исходного кода

Added support for third-party logging facilities

Pierre-Olivier Latour 11 лет назад
Родитель
Сommit
c45053bc11

+ 47 - 29
GCDWebServer/Core/GCDWebServer.h

@@ -30,21 +30,6 @@
 #import "GCDWebServerRequest.h"
 #import "GCDWebServerResponse.h"
 
-/**
- *  Log levels used by GCDWebServer.
- *
- *  @warning kGCDWebServerLogLevel_Debug is only functional if the preprocessor
- *  constant "DEBUG" is is non-zero at build time.
- */
-typedef NS_ENUM(int, GCDWebServerLogLevel) {
-  kGCDWebServerLogLevel_Debug = 0,
-  kGCDWebServerLogLevel_Verbose,
-  kGCDWebServerLogLevel_Info,
-  kGCDWebServerLogLevel_Warning,
-  kGCDWebServerLogLevel_Error,
-  kGCDWebServerLogLevel_Exception,
-};
-
 /**
  *  The GCDWebServerMatchBlock is called for every handler added to the
  *  GCDWebServer whenever a new HTTP request has started (i.e. HTTP headers have
@@ -482,43 +467,76 @@ extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
 
 @end
 
+/**
+ *  GCDWebServer provides its own built-in logging facility which is used by
+ *  default. It simply sends log messages to stderr assuming it is connected
+ *  to a terminal type device.
+ *
+ *  GCDWebServer is also compatible with a limited set of third-party logging
+ *  facilities. If one of them is available at compile time, GCDWebServer will
+ *  automatically use it in place of the built-in one.
+ *
+ *  Currently supported third-party logging facilities are:
+ *  - XLFacility (by the same author as GCDWebServer): https://github.com/swisspol/XLFacility
+ *  - CocoaLumberjack: https://github.com/CocoaLumberjack/CocoaLumberjack
+ *
+ *  For both the built-in logging facility and CocoaLumberjack, the default
+ *  logging level is INFO (or DEBUG if the preprocessor constant "DEBUG"
+ *  evaluates to non-zero at compile time).
+ *
+ *  It's possible to have GCDWebServer use a custom logging facility by defining
+ *  the "__GCDWEBSERVER_LOGGING_HEADER__" preprocessor constant in Xcode build
+ *  settings to the name of a custom header file (escaped like \"MyLogging.h\").
+ *  This header file must define the following set of macros:
+ *
+ *    GWS_LOG_DEBUG(...)
+ *    GWS_LOG_VERBOSE(...)
+ *    GWS_LOG_INFO(...)
+ *    GWS_LOG_WARNING(...)
+ *    GWS_LOG_ERROR(...)
+ *    GWS_LOG_EXCEPTION(__EXCEPTION__)
+ *
+ *  IMPORTANT: Except for GWS_LOG_EXCEPTION() which gets passed an NSException,
+ *  these macros must behave like NSLog(). Furthermore the GWS_LOG_DEBUG() macro
+ *  should not do anything unless the preprocessor constant "DEBUG" evaluates to
+ *  non-zero.
+ *
+ *  The logging methods below send log messages to the same logging facility
+ *  used by GCDWebServer. They can be used for consistency wherever you interact
+ *  with GCDWebServer in your code (e.g. in the implementation of handlers).
+ */
 @interface GCDWebServer (Logging)
 
-#ifndef __GCDWEBSERVER_LOGGING_HEADER__
-
 /**
- *  Sets the current log level below which logged messages are discarded.
+ *  Sets the log level of the logging facility below which log messages are discarded.
  *
- *  The default level is INFO (or DEBUG if the preprocessor constant "DEBUG"
- *  is non-zero at build time).
- *  It can also be set at run time with the "logLevel" environment variable.
+ *  @warning The interpretation of the "level" argument depends on the logging
+ *  facility used at compile time.
  */
-+ (void)setLogLevel:(GCDWebServerLogLevel)level;
-
-#endif
++ (void)setLogLevel:(int)level;
 
 /**
- *  Logs a message with the kGCDWebServerLogLevel_Verbose level.
+ *  Logs a message to the logging facility at the VERBOSE level.
  */
 - (void)logVerbose:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
 
 /**
- *  Logs a message with the kGCDWebServerLogLevel_Info level.
+ *  Logs a message to the logging facility at the INFO level.
  */
 - (void)logInfo:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
 
 /**
- *  Logs a message with the kGCDWebServerLogLevel_Warning level.
+ *  Logs a message to the logging facility at the WARNING level.
  */
 - (void)logWarning:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
 
 /**
- *  Logs a message with the kGCDWebServerLogLevel_Error level.
+ *  Logs a message to the logging facility at the ERROR level.
  */
 - (void)logError:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
 
 /**
- *  Logs an exception with the kGCDWebServerLogLevel_Exception level.
+ *  Logs an exception to the logging facility at the EXCEPTION level.
  */
 - (void)logException:(NSException*)exception;
 

+ 93 - 90
GCDWebServer/Core/GCDWebServer.m

@@ -61,11 +61,17 @@ NSString* const GCDWebServerOption_AutomaticallySuspendInBackground = @"Automati
 NSString* const GCDWebServerAuthenticationMethod_Basic = @"Basic";
 NSString* const GCDWebServerAuthenticationMethod_DigestAccess = @"DigestAccess";
 
-#ifndef __GCDWEBSERVER_LOGGING_HEADER__
+#if defined(__GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__)
 #if DEBUG
-GCDWebServerLogLevel GCDLogLevel = kGCDWebServerLogLevel_Debug;
+GCDWebServerLoggingLevel GCDWebServerLogLevel = kGCDWebServerLoggingLevel_Debug;
 #else
-GCDWebServerLogLevel GCDLogLevel = kGCDWebServerLogLevel_Info;
+GCDWebServerLoggingLevel GCDWebServerLogLevel = kGCDWebServerLoggingLevel_Info;
+#endif
+#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
+#if DEBUG
+int GCDWebServerLogLevel = LOG_LEVEL_DEBUG;
+#else
+int GCDWebServerLogLevel = LOG_LEVEL_INFO;
 #endif
 #endif
 
@@ -73,16 +79,22 @@ GCDWebServerLogLevel GCDLogLevel = kGCDWebServerLogLevel_Info;
 static BOOL _run;
 #endif
 
-#ifndef __GCDWEBSERVER_LOGGING_HEADER__
+#ifdef __GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__
 
-void GCDLogMessage(GCDWebServerLogLevel level, NSString* format, ...) {
+void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* format, ...) {
   static const char* levelNames[] = {"DEBUG", "VERBOSE", "INFO", "WARNING", "ERROR", "EXCEPTION"};
-  va_list arguments;
-  va_start(arguments, format);
-  NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
-  va_end(arguments);
-  fprintf(stderr, "[%s] %s\n", levelNames[level], [message UTF8String]);
-  ARC_RELEASE(message);
+  static int enableLogging = -1;
+  if (enableLogging < 0) {
+    enableLogging = (isatty(STDERR_FILENO) ? 1 : 0);
+  }
+  if (enableLogging) {
+    va_list arguments;
+    va_start(arguments, format);
+    NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
+    va_end(arguments);
+    fprintf(stderr, "[%s] %s\n", levelNames[level], [message UTF8String]);
+    ARC_RELEASE(message);
+  }
 }
 
 #endif
@@ -177,17 +189,6 @@ static void _ExecuteMainThreadRunLoopSources() {
             authenticationBasicAccounts=_authenticationBasicAccounts, authenticationDigestAccounts=_authenticationDigestAccounts,
             shouldAutomaticallyMapHEADToGET=_mapHEADToGET;
 
-#ifndef __GCDWEBSERVER_LOGGING_HEADER__
-
-+ (void)load {
-  const char* logLevel = getenv("logLevel");
-  if (logLevel) {
-    GCDLogLevel = atoi(logLevel);
-  }
-}
-
-#endif
-
 + (void)initialize {
   GCDWebServerInitializeFunctions();
 }
@@ -205,10 +206,10 @@ static void _ExecuteMainThreadRunLoopSources() {
 }
 
 - (void)dealloc {
-  DCHECK(_connected == NO);
-  DCHECK(_activeConnections == 0);
-  DCHECK(_options == nil);  // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
-  DCHECK(_disconnectTimer == NULL);  // The server can never be dealloc'ed while the disconnect timer is pending because of the retain-cycle
+  GWS_DCHECK(_connected == NO);
+  GWS_DCHECK(_activeConnections == 0);
+  GWS_DCHECK(_options == nil);  // The server can never be dealloc'ed while running because of the retain-cycle with the dispatch source
+  GWS_DCHECK(_disconnectTimer == NULL);  // The server can never be dealloc'ed while the disconnect timer is pending because of the retain-cycle
   
   ARC_RELEASE(_handlers);
   ARC_DISPATCH_RELEASE(_sourceSemaphore);
@@ -221,17 +222,17 @@ static void _ExecuteMainThreadRunLoopSources() {
 
 // Always called on main thread
 - (void)_startBackgroundTask {
-  DCHECK([NSThread isMainThread]);
+  GWS_DCHECK([NSThread isMainThread]);
   if (_backgroundTask == UIBackgroundTaskInvalid) {
-    LOG_DEBUG(@"Did start background task");
+    GWS_LOG_DEBUG(@"Did start background task");
     _backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
       
-      LOG_WARNING(@"Application is being suspended while %@ is still connected", [self class]);
+      GWS_LOG_WARNING(@"Application is being suspended while %@ is still connected", [self class]);
       [self _endBackgroundTask];
       
     }];
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
 }
 
@@ -239,10 +240,10 @@ static void _ExecuteMainThreadRunLoopSources() {
 
 // Always called on main thread
 - (void)_didConnect {
-  DCHECK([NSThread isMainThread]);
-  DCHECK(_connected == NO);
+  GWS_DCHECK([NSThread isMainThread]);
+  GWS_DCHECK(_connected == NO);
   _connected = YES;
-  LOG_DEBUG(@"Did connect");
+  GWS_LOG_DEBUG(@"Did connect");
   
 #if TARGET_OS_IPHONE
   [self _startBackgroundTask];
@@ -256,7 +257,7 @@ static void _ExecuteMainThreadRunLoopSources() {
 - (void)willStartConnection:(GCDWebServerConnection*)connection {
   dispatch_sync(_syncQueue, ^{
     
-    DCHECK(_activeConnections >= 0);
+    GWS_DCHECK(_activeConnections >= 0);
     if (_activeConnections == 0) {
       dispatch_async(dispatch_get_main_queue(), ^{
         if (_disconnectTimer) {
@@ -278,16 +279,16 @@ static void _ExecuteMainThreadRunLoopSources() {
 
 // Always called on main thread
 - (void)_endBackgroundTask {
-  DCHECK([NSThread isMainThread]);
+  GWS_DCHECK([NSThread isMainThread]);
   if (_backgroundTask != UIBackgroundTaskInvalid) {
     if (_suspendInBackground && ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) && _source) {
       [self _stop];
     }
     [[UIApplication sharedApplication] endBackgroundTask:_backgroundTask];
     _backgroundTask = UIBackgroundTaskInvalid;
-    LOG_DEBUG(@"Did end background task");
+    GWS_LOG_DEBUG(@"Did end background task");
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
 }
 
@@ -295,10 +296,10 @@ static void _ExecuteMainThreadRunLoopSources() {
 
 // Always called on main thread
 - (void)_didDisconnect {
-  DCHECK([NSThread isMainThread]);
-  DCHECK(_connected == YES);
+  GWS_DCHECK([NSThread isMainThread]);
+  GWS_DCHECK(_connected == YES);
   _connected = NO;
-  LOG_DEBUG(@"Did disconnect");
+  GWS_LOG_DEBUG(@"Did disconnect");
   
 #if TARGET_OS_IPHONE
   [self _endBackgroundTask];
@@ -311,7 +312,7 @@ static void _ExecuteMainThreadRunLoopSources() {
 
 - (void)didEndConnection:(GCDWebServerConnection*)connection {
   dispatch_sync(_syncQueue, ^{
-    DCHECK(_activeConnections > 0);
+    GWS_DCHECK(_activeConnections > 0);
     _activeConnections -= 1;
     if (_activeConnections == 0) {
       dispatch_async(dispatch_get_main_queue(), ^{
@@ -321,7 +322,7 @@ static void _ExecuteMainThreadRunLoopSources() {
             CFRelease(_disconnectTimer);
           }
           _disconnectTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + _disconnectDelay, 0.0, 0, 0, ^(CFRunLoopTimerRef timer) {
-            DCHECK([NSThread isMainThread]);
+            GWS_DCHECK([NSThread isMainThread]);
             [self _didDisconnect];
             CFRelease(_disconnectTimer);
             _disconnectTimer = NULL;
@@ -352,40 +353,40 @@ static void _ExecuteMainThreadRunLoopSources() {
 }
 
 - (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock asyncProcessBlock:(GCDWebServerAsyncProcessBlock)processBlock {
-  DCHECK(_options == nil);
+  GWS_DCHECK(_options == nil);
   GCDWebServerHandler* handler = [[GCDWebServerHandler alloc] initWithMatchBlock:matchBlock asyncProcessBlock:processBlock];
   [_handlers insertObject:handler atIndex:0];
   ARC_RELEASE(handler);
 }
 
 - (void)removeAllHandlers {
-  DCHECK(_options == nil);
+  GWS_DCHECK(_options == nil);
   [_handlers removeAllObjects];
 }
 
 static void _NetServiceRegisterCallBack(CFNetServiceRef service, CFStreamError* error, void* info) {
-  DCHECK([NSThread isMainThread]);
+  GWS_DCHECK([NSThread isMainThread]);
   @autoreleasepool {
     if (error->error) {
-      LOG_ERROR(@"Bonjour registration error %i (domain %i)", (int)error->error, (int)error->domain);
+      GWS_LOG_ERROR(@"Bonjour registration error %i (domain %i)", (int)error->error, (int)error->domain);
     } else {
       GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
-      LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]);
+      GWS_LOG_VERBOSE(@"Bonjour registration complete for %@", [server class]);
       CFNetServiceResolveWithTimeout(server->_resolutionService, 1.0, NULL);
     }
   }
 }
 
 static void _NetServiceResolveCallBack(CFNetServiceRef service, CFStreamError* error, void* info) {
-  DCHECK([NSThread isMainThread]);
+  GWS_DCHECK([NSThread isMainThread]);
   @autoreleasepool {
     if (error->error) {
       if ((error->domain != kCFStreamErrorDomainNetServices) && (error->error != kCFNetServicesErrorTimeout)) {
-        LOG_ERROR(@"Bonjour resolution error %i (domain %i)", (int)error->error, (int)error->domain);
+        GWS_LOG_ERROR(@"Bonjour resolution error %i (domain %i)", (int)error->error, (int)error->domain);
       }
     } else {
       GCDWebServer* server = (ARC_BRIDGE GCDWebServer*)info;
-      LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL);
+      GWS_LOG_INFO(@"%@ now reachable at %@", [server class], server.bonjourServerURL);
       if ([server.delegate respondsToSelector:@selector(webServerDidCompleteBonjourRegistration:)]) {
         [server.delegate webServerDidCompleteBonjourRegistration:server];
       }
@@ -409,7 +410,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
 }
 
 - (BOOL)_start:(NSError**)error {
-  DCHECK(_source == NULL);
+  GWS_DCHECK(_source == NULL);
   
   NSUInteger port = [_GetOption(_options, GCDWebServerOption_Port, @0) unsignedIntegerValue];
   NSString* bonjourName = _GetOption(_options, GCDWebServerOption_BonjourName, @"");
@@ -428,7 +429,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
     addr4.sin_addr.s_addr = htonl(INADDR_ANY);
     if (bind(listeningSocket, (void*)&addr4, sizeof(addr4)) == 0) {
       if (listen(listeningSocket, (int)maxPendingConnections) == 0) {
-        LOG_DEBUG(@"Did open listening socket %i", listeningSocket);
+        GWS_LOG_DEBUG(@"Did open listening socket %i", listeningSocket);
         _serverName = [_GetOption(_options, GCDWebServerOption_ServerName, NSStringFromClass([self class])) copy];
         NSString* authenticationMethod = _GetOption(_options, GCDWebServerOption_AuthenticationMethod, nil);
         if ([authenticationMethod isEqualToString:GCDWebServerAuthenticationMethod_Basic]) {
@@ -455,9 +456,9 @@ static inline NSString* _EncodeBase64(NSString* string) {
           @autoreleasepool {
             int result = close(listeningSocket);
             if (result != 0) {
-              LOG_ERROR(@"Failed closing listening socket: %s (%i)", strerror(errno), errno);
+              GWS_LOG_ERROR(@"Failed closing listening socket: %s (%i)", strerror(errno), errno);
             } else {
-              LOG_DEBUG(@"Did close listening socket %i", listeningSocket);
+              GWS_LOG_DEBUG(@"Did close listening socket %i", listeningSocket);
             }
           }
           dispatch_semaphore_signal(_sourceSemaphore);
@@ -478,7 +479,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
               if (getsockname(socket, &localSockAddr, &localAddrLen) == 0) {
                 localAddress = [NSData dataWithBytes:&localSockAddr length:localAddrLen];
               } else {
-                DNOT_REACHED();
+                GWS_DNOT_REACHED();
               }
               
               int noSigPipe = 1;
@@ -491,7 +492,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
               [connection release];
 #endif
             } else {
-              LOG_ERROR(@"Failed accepting socket: %s (%i)", strerror(errno), errno);
+              GWS_LOG_ERROR(@"Failed accepting socket: %s (%i)", strerror(errno), errno);
             }
           }
           
@@ -504,7 +505,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
             struct sockaddr_in* sockaddr = (struct sockaddr_in*)&addr;
             _port = ntohs(sockaddr->sin_port);
           } else {
-            LOG_ERROR(@"Failed retrieving socket address: %s (%i)", strerror(errno), errno);
+            GWS_LOG_ERROR(@"Failed retrieving socket address: %s (%i)", strerror(errno), errno);
           }
         } else {
           _port = port;
@@ -526,12 +527,12 @@ static inline NSString* _EncodeBase64(NSString* string) {
               CFNetServiceScheduleWithRunLoop(_resolutionService, CFRunLoopGetMain(), kCFRunLoopCommonModes);
             }
           } else {
-            LOG_ERROR(@"Failed creating CFNetService");
+            GWS_LOG_ERROR(@"Failed creating CFNetService");
           }
         }
         
         dispatch_resume(_source);
-        LOG_INFO(@"%@ started on port %i and reachable at %@", [self class], (int)_port, self.serverURL);
+        GWS_LOG_INFO(@"%@ started on port %i and reachable at %@", [self class], (int)_port, self.serverURL);
         if ([_delegate respondsToSelector:@selector(webServerDidStart:)]) {
           dispatch_async(dispatch_get_main_queue(), ^{
             [_delegate webServerDidStart:self];
@@ -541,27 +542,27 @@ static inline NSString* _EncodeBase64(NSString* string) {
         if (error) {
           *error = GCDWebServerMakePosixError(errno);
         }
-        LOG_ERROR(@"Failed starting listening socket: %s (%i)", strerror(errno), errno);
+        GWS_LOG_ERROR(@"Failed starting listening socket: %s (%i)", strerror(errno), errno);
         close(listeningSocket);
       }
     } else {
       if (error) {
         *error = GCDWebServerMakePosixError(errno);
       }
-      LOG_ERROR(@"Failed binding listening socket: %s (%i)", strerror(errno), errno);
+      GWS_LOG_ERROR(@"Failed binding listening socket: %s (%i)", strerror(errno), errno);
       close(listeningSocket);
     }
   } else {
     if (error) {
       *error = GCDWebServerMakePosixError(errno);
     }
-    LOG_ERROR(@"Failed creating listening socket: %s (%i)", strerror(errno), errno);
+    GWS_LOG_ERROR(@"Failed creating listening socket: %s (%i)", strerror(errno), errno);
   }
   return (_source ? YES : NO);
 }
 
 - (void)_stop {
-  DCHECK(_source != NULL);
+  GWS_DCHECK(_source != NULL);
   
   if (_registrationService) {
     if (_resolutionService) {
@@ -602,7 +603,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
     }
   });
   
-  LOG_INFO(@"%@ stopped", [self class]);
+  GWS_LOG_INFO(@"%@ stopped", [self class]);
   if ([_delegate respondsToSelector:@selector(webServerDidStop:)]) {
     dispatch_async(dispatch_get_main_queue(), ^{
       [_delegate webServerDidStop:self];
@@ -613,16 +614,16 @@ static inline NSString* _EncodeBase64(NSString* string) {
 #if TARGET_OS_IPHONE
 
 - (void)_didEnterBackground:(NSNotification*)notification {
-  DCHECK([NSThread isMainThread]);
-  LOG_DEBUG(@"Did enter background");
+  GWS_DCHECK([NSThread isMainThread]);
+  GWS_LOG_DEBUG(@"Did enter background");
   if ((_backgroundTask == UIBackgroundTaskInvalid) && _source) {
     [self _stop];
   }
 }
 
 - (void)_willEnterForeground:(NSNotification*)notification {
-  DCHECK([NSThread isMainThread]);
-  LOG_DEBUG(@"Will enter foreground");
+  GWS_DCHECK([NSThread isMainThread]);
+  GWS_LOG_DEBUG(@"Will enter foreground");
   if (!_source) {
     [self _start:NULL];  // TODO: There's probably nothing we can do on failure
   }
@@ -652,7 +653,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
 #endif
     return YES;
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
   return NO;
 }
@@ -675,7 +676,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
     ARC_RELEASE(_options);
     _options = nil;
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
 }
 
@@ -733,7 +734,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
 }
 
 - (BOOL)runWithOptions:(NSDictionary*)options error:(NSError**)error {
-  DCHECK([NSThread isMainThread]);
+  GWS_DCHECK([NSThread isMainThread]);
   BOOL success = NO;
   _run = YES;
   void (*termHandler)(int) = signal(SIGTERM, _SignalHandler);
@@ -796,7 +797,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
       
     } asyncProcessBlock:block];
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
 }
 
@@ -834,7 +835,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
       
     } asyncProcessBlock:block];
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
 }
 
@@ -881,7 +882,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
     if (![file hasPrefix:@"."]) {
       NSString* type = [[enumerator fileAttributes] objectForKey:NSFileType];
       NSString* escapedFile = [file stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-      DCHECK(escapedFile);
+      GWS_DCHECK(escapedFile);
       if ([type isEqualToString:NSFileTypeRegular]) {
         [html appendFormat:@"<li><a href=\"%@\">%@</a></li>\n", escapedFile, file];
       } else if ([type isEqualToString:NSFileTypeDirectory]) {
@@ -945,7 +946,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
       
     }];
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
 }
 
@@ -953,44 +954,46 @@ static inline NSString* _EncodeBase64(NSString* string) {
 
 @implementation GCDWebServer (Logging)
 
-#ifndef __GCDWEBSERVER_LOGGING_HEADER__
-
-+ (void)setLogLevel:(GCDWebServerLogLevel)level {
-  GCDLogLevel = level;
-}
-
++ (void)setLogLevel:(int)level {
+#if defined(__GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__)
+  [XLSharedFacility setMinLogLevel:level];
+#elif defined(__GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__)
+  GCDWebServerLogLevel = level;
+#else
+  GCDWebServerLogLevel = level;
 #endif
+}
 
 - (void)logVerbose:(NSString*)format, ... {
   va_list arguments;
   va_start(arguments, format);
-  LOG_VERBOSE(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
+  GWS_LOG_VERBOSE(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
   va_end(arguments);
 }
 
 - (void)logInfo:(NSString*)format, ... {
   va_list arguments;
   va_start(arguments, format);
-  LOG_INFO(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
+  GWS_LOG_INFO(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
   va_end(arguments);
 }
 
 - (void)logWarning:(NSString*)format, ... {
   va_list arguments;
   va_start(arguments, format);
-  LOG_WARNING(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
+  GWS_LOG_WARNING(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
   va_end(arguments);
 }
 
 - (void)logError:(NSString*)format, ... {
   va_list arguments;
   va_start(arguments, format);
-  LOG_ERROR(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
+  GWS_LOG_ERROR(@"%@", ARC_AUTORELEASE([[NSString alloc] initWithFormat:format arguments:arguments]));
   va_end(arguments);
 }
 
 - (void)logException:(NSException*)exception {
-  LOG_EXCEPTION(exception);
+  GWS_LOG_EXCEPTION(exception);
 }
 
 @end
@@ -1047,7 +1050,7 @@ static CFHTTPMessageRef _CreateHTTPMessageFromPerformingRequest(NSData* inData,
           outData.length = length;
           response = _CreateHTTPMessageFromData(outData, NO);
         } else {
-          DNOT_REACHED();
+          GWS_DNOT_REACHED();
         }
         ARC_RELEASE(outData);
       }
@@ -1067,7 +1070,7 @@ static void _LogResult(NSString* format, ...) {
 }
 
 - (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path {
-  DCHECK([NSThread isMainThread]);
+  GWS_DCHECK([NSThread isMainThread]);
   NSArray* ignoredHeaders = @[@"Date", @"Etag"];  // Dates are always different by definition and ETags depend on file system node IDs
   NSInteger result = -1;
   if ([self startWithOptions:options error:NULL]) {
@@ -1159,7 +1162,7 @@ static void _LogResult(NSString* format, ...) {
                     CFRelease(expectedResponse);
                   }
                 } else {
-                  DNOT_REACHED();
+                  GWS_DNOT_REACHED();
                 }
                 break;
               }
@@ -1167,7 +1170,7 @@ static void _LogResult(NSString* format, ...) {
             CFRelease(request);
           }
         } else {
-          DNOT_REACHED();
+          GWS_DNOT_REACHED();
         }
         _LogResult(@"");
         if (!success) {

+ 61 - 61
GCDWebServer/Core/GCDWebServerConnection.m

@@ -99,14 +99,14 @@ static int32_t _connectionCounter = 0;
           block(YES);
         } else {
           if (_bytesRead > 0) {
-            LOG_ERROR(@"No more data available on socket %i", _socket);
+            GWS_LOG_ERROR(@"No more data available on socket %i", _socket);
           } else {
-            LOG_WARNING(@"No data received from socket %i", _socket);
+            GWS_LOG_WARNING(@"No data received from socket %i", _socket);
           }
           block(NO);
         }
       } else {
-        LOG_ERROR(@"Error while reading from socket %i: %s (%i)", _socket, strerror(error), error);
+        GWS_LOG_ERROR(@"Error while reading from socket %i: %s (%i)", _socket, strerror(error), error);
         block(NO);
       }
     }
@@ -115,7 +115,7 @@ static int32_t _connectionCounter = 0;
 }
 
 - (void)_readHeaders:(NSMutableData*)headersData withCompletionBlock:(ReadHeadersCompletionBlock)block {
-  DCHECK(_requestMessage);
+  GWS_DCHECK(_requestMessage);
   [self _readData:headersData withLength:NSUIntegerMax completionBlock:^(BOOL success) {
     
     if (success) {
@@ -128,11 +128,11 @@ static int32_t _connectionCounter = 0;
           if (CFHTTPMessageIsHeaderComplete(_requestMessage)) {
             block([headersData subdataWithRange:NSMakeRange(length, headersData.length - length)]);
           } else {
-            LOG_ERROR(@"Failed parsing request headers from socket %i", _socket);
+            GWS_LOG_ERROR(@"Failed parsing request headers from socket %i", _socket);
             block(nil);
           }
         } else {
-          LOG_ERROR(@"Failed appending request headers data from socket %i", _socket);
+          GWS_LOG_ERROR(@"Failed appending request headers data from socket %i", _socket);
           block(nil);
         }
       }
@@ -144,7 +144,7 @@ static int32_t _connectionCounter = 0;
 }
 
 - (void)_readBodyWithRemainingLength:(NSUInteger)length completionBlock:(ReadBodyCompletionBlock)block {
-  DCHECK([_request hasBody] && ![_request usesChunkedTransferEncoding]);
+  GWS_DCHECK([_request hasBody] && ![_request usesChunkedTransferEncoding]);
   NSMutableData* bodyData = [[NSMutableData alloc] initWithCapacity:kBodyReadCapacity];
   [self _readData:bodyData withLength:length completionBlock:^(BOOL success) {
     
@@ -159,13 +159,13 @@ static int32_t _connectionCounter = 0;
             block(YES);
           }
         } else {
-          LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
+          GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
           block(NO);
         }
       } else {
-        LOG_ERROR(@"Unexpected extra content reading request body on socket %i", _socket);
+        GWS_LOG_ERROR(@"Unexpected extra content reading request body on socket %i", _socket);
         block(NO);
-        DNOT_REACHED();
+        GWS_DNOT_REACHED();
       }
     } else {
       block(NO);
@@ -185,7 +185,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 }
 
 - (void)_readNextBodyChunk:(NSMutableData*)chunkData completionBlock:(ReadBodyCompletionBlock)block {
-  DCHECK([_request hasBody] && [_request usesChunkedTransferEncoding]);
+  GWS_DCHECK([_request hasBody] && [_request usesChunkedTransferEncoding]);
   
   while (1) {
     NSRange range = [chunkData rangeOfData:_CRLFData options:0 range:NSMakeRange(0, chunkData.length)];
@@ -205,12 +205,12 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
           if ([_request performWriteData:[chunkData subdataWithRange:NSMakeRange(range.location + range.length, length)] error:&error]) {
             [chunkData replaceBytesInRange:NSMakeRange(0, range.location + range.length + length + 2) withBytes:NULL length:0];
           } else {
-            LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
+            GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
             block(NO);
             return;
           }
         } else {
-          LOG_ERROR(@"Missing terminating CRLF sequence for chunk reading request body on socket %i", _socket);
+          GWS_LOG_ERROR(@"Missing terminating CRLF sequence for chunk reading request body on socket %i", _socket);
           block(NO);
           return;
         }
@@ -222,7 +222,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
         }
       }
     } else {
-      LOG_ERROR(@"Invalid chunk length reading request body on socket %i", _socket);
+      GWS_LOG_ERROR(@"Invalid chunk length reading request body on socket %i", _socket);
       block(NO);
       return;
     }
@@ -258,11 +258,11 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
     
     @autoreleasepool {
       if (error == 0) {
-        DCHECK(remainingData == NULL);
+        GWS_DCHECK(remainingData == NULL);
         [self didWriteBytes:data.bytes length:data.length];
         block(YES);
       } else {
-        LOG_ERROR(@"Error while writing to socket %i: %s (%i)", _socket, strerror(error), error);
+        GWS_LOG_ERROR(@"Error while writing to socket %i: %s (%i)", _socket, strerror(error), error);
         block(NO);
       }
     }
@@ -272,14 +272,14 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 }
 
 - (void)_writeHeadersWithCompletionBlock:(WriteHeadersCompletionBlock)block {
-  DCHECK(_responseMessage);
+  GWS_DCHECK(_responseMessage);
   CFDataRef data = CFHTTPMessageCopySerializedMessage(_responseMessage);
   [self _writeData:(ARC_BRIDGE NSData*)data withCompletionBlock:block];
   CFRelease(data);
 }
 
 - (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block {
-  DCHECK([_response hasBody]);
+  GWS_DCHECK([_response hasBody]);
   NSError* error = nil;
   NSData* data = [_response performReadData:&error];
   if (data) {
@@ -289,7 +289,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
         size_t hexLength = strlen(hexString);
         NSData* chunk = [NSMutableData dataWithLength:(hexLength + 2 + data.length + 2)];
         if (chunk == nil) {
-          LOG_ERROR(@"Failed allocating memory for response body chunk for socket %i: %@", _socket, error);
+          GWS_LOG_ERROR(@"Failed allocating memory for response body chunk for socket %i: %@", _socket, error);
           block(NO);
           return;
         }
@@ -325,7 +325,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
       }
     }
   } else {
-    LOG_ERROR(@"Failed reading response body for socket %i: %@", _socket, error);
+    GWS_LOG_ERROR(@"Failed reading response body for socket %i: %@", _socket, error);
     block(NO);
   }
 }
@@ -339,11 +339,11 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 + (void)initialize {
   if (_CRLFData == nil) {
     _CRLFData = [[NSData alloc] initWithBytes:"\r\n" length:2];
-    DCHECK(_CRLFData);
+    GWS_DCHECK(_CRLFData);
   }
   if (_CRLFCRLFData == nil) {
     _CRLFCRLFData = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
-    DCHECK(_CRLFCRLFData);
+    GWS_DCHECK(_CRLFCRLFData);
   }
   if (_continueData == nil) {
     CFHTTPMessageRef message = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 100, NULL, kCFHTTPVersion1_1);
@@ -353,7 +353,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
     _continueData = (NSData*)CFHTTPMessageCopySerializedMessage(message);
 #endif
     CFRelease(message);
-    DCHECK(_continueData);
+    GWS_DCHECK(_continueData);
   }
   if (_lastChunkData == nil) {
     _lastChunkData = [[NSData alloc] initWithBytes:"0\r\n\r\n" length:5];
@@ -374,7 +374,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 }
 
 - (void)_startProcessingRequest {
-  DCHECK(_responseMessage == NULL);
+  GWS_DCHECK(_responseMessage == NULL);
   
   GCDWebServerResponse* preflightResponse = [self preflightRequest:_request];
   if (preflightResponse) {
@@ -388,7 +388,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 
 // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
 - (void)_finishProcessingRequest:(GCDWebServerResponse*)response {
-  DCHECK(_responseMessage == NULL);
+  GWS_DCHECK(_responseMessage == NULL);
   BOOL hasBody = NO;
   
   if (response) {
@@ -401,7 +401,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
     }
     NSError* error = nil;
     if (hasBody && ![response performOpen:&error]) {
-      LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
+      GWS_LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
     } else {
       _response = ARC_RETAIN(response);
     }
@@ -458,16 +458,16 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 - (void)_readBodyWithLength:(NSUInteger)length initialData:(NSData*)initialData {
   NSError* error = nil;
   if (![_request performOpen:&error]) {
-    LOG_ERROR(@"Failed opening request body for socket %i: %@", _socket, error);
+    GWS_LOG_ERROR(@"Failed opening request body for socket %i: %@", _socket, error);
     [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
     return;
   }
   
   if (initialData.length) {
     if (![_request performWriteData:initialData error:&error]) {
-      LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
+      GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
       if (![_request performClose:&error]) {
-        LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+        GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
       }
       [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
       return;
@@ -482,7 +482,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
       if ([_request performClose:&localError]) {
         [self _startProcessingRequest];
       } else {
-        LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+        GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
         [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
       }
       
@@ -491,7 +491,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
     if ([_request performClose:&error]) {
       [self _startProcessingRequest];
     } else {
-      LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+      GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
       [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
     }
   }
@@ -500,7 +500,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
 - (void)_readChunkedBodyWithInitialData:(NSData*)initialData {
   NSError* error = nil;
   if (![_request performOpen:&error]) {
-    LOG_ERROR(@"Failed opening request body for socket %i: %@", _socket, error);
+    GWS_LOG_ERROR(@"Failed opening request body for socket %i: %@", _socket, error);
     [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
     return;
   }
@@ -512,7 +512,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
     if ([_request performClose:&localError]) {
       [self _startProcessingRequest];
     } else {
-      LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+      GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
       [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
     }
     
@@ -535,7 +535,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
       NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(_requestMessage));
       if (requestURL) {
         requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders];
-        DCHECK(requestURL);
+        GWS_DCHECK(requestURL);
       }
       NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(ARC_BRIDGE_RELEASE(CFURLCopyPath((CFURLRef)requestURL))) : nil;  // Don't use -[NSURL path] which strips the ending slash
       NSString* queryString = requestURL ? ARC_BRIDGE_RELEASE(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil;  // Don't use -[NSURL query] to make sure query is not unescaped;
@@ -566,7 +566,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
                     
                   }];
                 } else {
-                  LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket);
+                  GWS_LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket);
                   [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_ExpectationFailed];
                 }
               } else {
@@ -577,7 +577,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
                 }
               }
             } else {
-              LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket);
+              GWS_LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket);
               [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_BadRequest];
             }
           } else {
@@ -585,12 +585,12 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
           }
         } else {
           _request = [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:requestPath query:requestQuery];
-          DCHECK(_request);
+          GWS_DCHECK(_request);
           [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_MethodNotAllowed];
         }
       } else {
         [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
-        DNOT_REACHED();
+        GWS_DNOT_REACHED();
       }
     } else {
       [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
@@ -606,7 +606,7 @@ 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);
+    GWS_LOG_DEBUG(@"Did open connection on socket %i", _socket);
     
     [_server willStartConnection:self];
     
@@ -630,7 +630,7 @@ static NSString* _StringFromAddressData(NSData* data) {
   if (getnameinfo(addr, addr->sa_len, hostBuffer, sizeof(hostBuffer), serviceBuffer, sizeof(serviceBuffer), NI_NUMERICHOST | NI_NUMERICSERV | NI_NOFQDN) >= 0) {
     string = [NSString stringWithFormat:@"%s:%s", hostBuffer, serviceBuffer];
   } else {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
   }
   return string;
 }
@@ -646,9 +646,9 @@ static NSString* _StringFromAddressData(NSData* data) {
 - (void)dealloc {
   int result = close(_socket);
   if (result != 0) {
-    LOG_ERROR(@"Failed closing socket %i for connection: %s (%i)", _socket, strerror(errno), errno);
+    GWS_LOG_ERROR(@"Failed closing socket %i for connection: %s (%i)", _socket, strerror(errno), errno);
   } else {
-    LOG_DEBUG(@"Did close connection on socket %i", _socket);
+    GWS_LOG_DEBUG(@"Did close connection on socket %i", _socket);
   }
   
   if (_opened) {
@@ -689,11 +689,11 @@ static NSString* _StringFromAddressData(NSData* data) {
     
     _requestPath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
     _requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-    DCHECK(_requestFD > 0);
+    GWS_DCHECK(_requestFD > 0);
     
     _responsePath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
     _responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-    DCHECK(_responseFD > 0);
+    GWS_DCHECK(_responseFD > 0);
   }
 #endif
   
@@ -701,12 +701,12 @@ static NSString* _StringFromAddressData(NSData* data) {
 }
 
 - (void)didReadBytes:(const void*)bytes length:(NSUInteger)length {
-  LOG_DEBUG(@"Connection received %lu bytes on socket %i", (unsigned long)length, _socket);
+  GWS_LOG_DEBUG(@"Connection received %lu bytes on socket %i", (unsigned long)length, _socket);
   _bytesRead += length;
   
 #ifdef __GCDWEBSERVER_ENABLE_TESTING__
   if ((_requestFD > 0) && (write(_requestFD, bytes, length) != (ssize_t)length)) {
-    LOG_ERROR(@"Failed recording request data: %s (%i)", strerror(errno), errno);
+    GWS_LOG_ERROR(@"Failed recording request data: %s (%i)", strerror(errno), errno);
     close(_requestFD);
     _requestFD = 0;
   }
@@ -714,12 +714,12 @@ static NSString* _StringFromAddressData(NSData* data) {
 }
 
 - (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length {
-  LOG_DEBUG(@"Connection sent %lu bytes on socket %i", (unsigned long)length, _socket);
+  GWS_LOG_DEBUG(@"Connection sent %lu bytes on socket %i", (unsigned long)length, _socket);
   _bytesWritten += length;
   
 #ifdef __GCDWEBSERVER_ENABLE_TESTING__
   if ((_responseFD > 0) && (write(_responseFD, bytes, length) != (ssize_t)length)) {
-    LOG_ERROR(@"Failed recording response data: %s (%i)", strerror(errno), errno);
+    GWS_LOG_ERROR(@"Failed recording response data: %s (%i)", strerror(errno), errno);
     close(_responseFD);
     _responseFD = 0;
   }
@@ -732,7 +732,7 @@ static NSString* _StringFromAddressData(NSData* data) {
 
 // https://tools.ietf.org/html/rfc2617
 - (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request {
-  LOG_DEBUG(@"Connection on socket %i preflighting request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
+  GWS_LOG_DEBUG(@"Connection on socket %i preflighting request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
   GCDWebServerResponse* response = nil;
   if (_server.authenticationBasicAccounts) {
     __block BOOL authenticated = NO;
@@ -782,12 +782,12 @@ static NSString* _StringFromAddressData(NSData* data) {
 }
 
 - (void)processRequest:(GCDWebServerRequest*)request completion:(GCDWebServerCompletionBlock)completion {
-  LOG_DEBUG(@"Connection on socket %i processing request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
+  GWS_LOG_DEBUG(@"Connection on socket %i processing request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
   @try {
     _handler.asyncProcessBlock(request, completion);
   }
   @catch (NSException* exception) {
-    LOG_EXCEPTION(exception);
+    GWS_LOG_EXCEPTION(exception);
   }
 }
 
@@ -813,20 +813,20 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET
     newResponse.cacheControlMaxAge = response.cacheControlMaxAge;
     newResponse.lastModifiedDate = response.lastModifiedDate;
     newResponse.eTag = response.eTag;
-    DCHECK(newResponse);
+    GWS_DCHECK(newResponse);
     return newResponse;
   }
   return response;
 }
 
 - (void)abortRequest:(GCDWebServerRequest*)request withStatusCode:(NSInteger)statusCode {
-  DCHECK(_responseMessage == NULL);
-  DCHECK((statusCode >= 400) && (statusCode < 600));
+  GWS_DCHECK(_responseMessage == NULL);
+  GWS_DCHECK((statusCode >= 400) && (statusCode < 600));
   [self _initializeResponseHeadersWithStatusCode:statusCode];
   [self _writeHeadersWithCompletionBlock:^(BOOL success) {
     ;  // Nothing more to do
   }];
-  LOG_DEBUG(@"Connection aborted with status code %i on socket %i", (int)statusCode, _socket);
+  GWS_LOG_DEBUG(@"Connection aborted with status code %i on socket %i", (int)statusCode, _socket);
 }
 
 - (void)close {
@@ -840,8 +840,8 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET
       success = [[NSFileManager defaultManager] moveItemAtPath:_requestPath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
     }
     if (!success) {
-      LOG_ERROR(@"Failed saving recorded request: %@", error);
-      DNOT_REACHED();
+      GWS_LOG_ERROR(@"Failed saving recorded request: %@", error);
+      GWS_DNOT_REACHED();
     }
     unlink([_requestPath fileSystemRepresentation]);
   }
@@ -855,17 +855,17 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET
       success = [[NSFileManager defaultManager] moveItemAtPath:_responsePath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
     }
     if (!success) {
-      LOG_ERROR(@"Failed saving recorded response: %@", error);
-      DNOT_REACHED();
+      GWS_LOG_ERROR(@"Failed saving recorded response: %@", error);
+      GWS_DNOT_REACHED();
     }
     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);
+    GWS_LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
   } else {
-    LOG_VERBOSE(@"[%@] %@ %i \"(invalid request)\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
+    GWS_LOG_VERBOSE(@"[%@] %@ %i \"(invalid request)\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
   }
 }
 

+ 6 - 6
GCDWebServer/Core/GCDWebServerFunctions.m

@@ -45,24 +45,24 @@ static dispatch_queue_t _dateFormatterQueue = NULL;
 
 // TODO: Handle RFC 850 and ANSI C's asctime() format
 void GCDWebServerInitializeFunctions() {
-  DCHECK([NSThread isMainThread]);  // NSDateFormatter should be initialized on main thread
+  GWS_DCHECK([NSThread isMainThread]);  // NSDateFormatter should be initialized on main thread
   if (_dateFormatterRFC822 == nil) {
     _dateFormatterRFC822 = [[NSDateFormatter alloc] init];
     _dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
     _dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
     _dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
-    DCHECK(_dateFormatterRFC822);
+    GWS_DCHECK(_dateFormatterRFC822);
   }
   if (_dateFormatterISO8601 == nil) {
     _dateFormatterISO8601 = [[NSDateFormatter alloc] init];
     _dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
     _dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'";
     _dateFormatterISO8601.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
-    DCHECK(_dateFormatterISO8601);
+    GWS_DCHECK(_dateFormatterISO8601);
   }
   if (_dateFormatterQueue == NULL) {
     _dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
-    DCHECK(_dateFormatterQueue);
+    GWS_DCHECK(_dateFormatterQueue);
   }
 }
 
@@ -210,8 +210,8 @@ NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
     if (unescapedKey && unescapedValue) {
       [parameters setObject:unescapedValue forKey:unescapedKey];
     } else {
-      LOG_WARNING(@"Failed parsing URL encoded form for key \"%@\" and value \"%@\"", key, value);
-      DNOT_REACHED();
+      GWS_LOG_WARNING(@"Failed parsing URL encoded form for key \"%@\" and value \"%@\"", key, value);
+      GWS_DNOT_REACHED();
     }
     
     if ([scanner isAtEnd]) {

+ 102 - 17
GCDWebServer/Core/GCDWebServerPrivate.h

@@ -27,6 +27,10 @@
 
 #import <os/object.h>
 
+/**
+ *  ARC <-> MRC compatibility macros.
+ */
+
 #if __has_feature(objc_arc)
 #define ARC_BRIDGE __bridge
 #define ARC_BRIDGE_RELEASE(__OBJECT__) CFBridgingRelease(__OBJECT__)
@@ -52,6 +56,10 @@
 #define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
 #endif
 
+/**
+ *  All GCDWebServer headers.
+ */
+
 #import "GCDWebServerHTTPStatusCodes.h"
 #import "GCDWebServerFunctions.h"
 
@@ -68,45 +76,122 @@
 #import "GCDWebServerFileResponse.h"
 #import "GCDWebServerStreamedResponse.h"
 
-#ifdef __GCDWEBSERVER_LOGGING_HEADER__
+/**
+ *  Automatically detect if XLFacility is available and if so use it as a
+ *  logging facility.
+ */
+
+#if defined(__has_include) && __has_include("XLFacilityMacros.h")
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__
+
+#import "XLFacilityMacros.h"
+
+#define GWS_LOG_DEBUG(...) XLOG_DEBUG(__VA_ARGS__)
+#define GWS_LOG_VERBOSE(...) XLOG_VERBOSE(__VA_ARGS__)
+#define GWS_LOG_INFO(...) XLOG_INFO(__VA_ARGS__)
+#define GWS_LOG_WARNING(...) XLOG_WARNING(__VA_ARGS__)
+#define GWS_LOG_ERROR(...) XLOG_ERROR(__VA_ARGS__)
+#define GWS_LOG_EXCEPTION(__EXCEPTION__) XLOG_EXCEPTION(__EXCEPTION__)
+
+#define GWS_DCHECK(__CONDITION__) XLOG_DEBUG_CHECK(__CONDITION__)
+#define GWS_DNOT_REACHED() XLOG_DEBUG_UNREACHABLE()
+
+/**
+ *  Automatically detect if CocoaLumberJack is available and if so use
+ *  it as a logging facility.
+ */
+
+#elif defined(__has_include) && __has_include("DDLogMacros.h")
+
+#import "DDLogMacros.h"
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__
+
+#undef LOG_LEVEL_DEF
+#define LOG_LEVEL_DEF GCDWebServerLogLevel
+extern int GCDWebServerLogLevel;
+
+#define GWS_LOG_DEBUG(...) DDLogDebug(__VA_ARGS__)
+#define GWS_LOG_VERBOSE(...) DDLogVerbose(__VA_ARGS__)
+#define GWS_LOG_INFO(...) DDLogInfo(__VA_ARGS__)
+#define GWS_LOG_WARNING(...) DDLogWarn(__VA_ARGS__)
+#define GWS_LOG_ERROR(...) DDLogError(__VA_ARGS__)
+#define GWS_LOG_EXCEPTION(__EXCEPTION__) DDLogError(@"%@", __EXCEPTION__)
+
+/**
+ *  Check if a custom logging facility should be used instead.
+ */
+
+#elif defined(__GCDWEBSERVER_LOGGING_HEADER__)
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
 
-// Define __GCDWEBSERVER_LOGGING_HEADER__ as a preprocessor constant to redirect GCDWebServer logging to your own system
-// This can be done in Xcode build settings like this:
-// GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = __GCDWEBSERVER_LOGGING_HEADER__=\"MyLoggingHeader.h\"
 #import __GCDWEBSERVER_LOGGING_HEADER__
 
+/**
+ *  If all of the above fail, then use GCDWebServer built-in
+ *  logging facility.
+ */
+
 #else
 
-extern GCDWebServerLogLevel GCDLogLevel;
-extern void GCDLogMessage(GCDWebServerLogLevel level, NSString* format, ...) NS_FORMAT_FUNCTION(2, 3);
+#define __GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__
 
-#define LOG_VERBOSE(...) do { if (GCDLogLevel <= kGCDWebServerLogLevel_Verbose) GCDLogMessage(kGCDWebServerLogLevel_Verbose, __VA_ARGS__); } while (0)
-#define LOG_INFO(...) do { if (GCDLogLevel <= kGCDWebServerLogLevel_Info) GCDLogMessage(kGCDWebServerLogLevel_Info, __VA_ARGS__); } while (0)
-#define LOG_WARNING(...) do { if (GCDLogLevel <= kGCDWebServerLogLevel_Warning) GCDLogMessage(kGCDWebServerLogLevel_Warning, __VA_ARGS__); } while (0)
-#define LOG_ERROR(...) do { if (GCDLogLevel <= kGCDWebServerLogLevel_Error) GCDLogMessage(kGCDWebServerLogLevel_Error, __VA_ARGS__); } while (0)
-#define LOG_EXCEPTION(__EXCEPTION__) do { if (GCDLogLevel <= kGCDWebServerLogLevel_Exception) GCDLogMessage(kGCDWebServerLogLevel_Exception, @"%@", __EXCEPTION__); } while (0)
+typedef NS_ENUM(int, GCDWebServerLoggingLevel) {
+  kGCDWebServerLoggingLevel_Debug = 0,
+  kGCDWebServerLoggingLevel_Verbose,
+  kGCDWebServerLoggingLevel_Info,
+  kGCDWebServerLoggingLevel_Warning,
+  kGCDWebServerLoggingLevel_Error,
+  kGCDWebServerLoggingLevel_Exception,
+};
+
+extern GCDWebServerLoggingLevel GCDWebServerLogLevel;
+extern void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* format, ...) NS_FORMAT_FUNCTION(2, 3);
 
 #if DEBUG
+#define GWS_LOG_DEBUG(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Debug) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Debug, __VA_ARGS__); } while (0)
+#else
+#define GWS_LOG_DEBUG(...)
+#endif
+#define GWS_LOG_VERBOSE(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Verbose) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Verbose, __VA_ARGS__); } while (0)
+#define GWS_LOG_INFO(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Info) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Info, __VA_ARGS__); } while (0)
+#define GWS_LOG_WARNING(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Warning) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Warning, __VA_ARGS__); } while (0)
+#define GWS_LOG_ERROR(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Error) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Error, __VA_ARGS__); } while (0)
+#define GWS_LOG_EXCEPTION(__EXCEPTION__) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Exception) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Exception, @"%@", __EXCEPTION__); } while (0)
 
-#define DCHECK(__CONDITION__) \
+#endif
+
+/**
+ *  Consistency check macros used when building Debug only.
+ */
+
+#if !defined(GWS_DCHECK) || !defined(GWS_DNOT_REACHED)
+
+#if DEBUG
+
+#define GWS_DCHECK(__CONDITION__) \
   do { \
     if (!(__CONDITION__)) { \
       abort(); \
     } \
   } while (0)
-#define DNOT_REACHED() abort()
-#define LOG_DEBUG(...) do { if (GCDLogLevel <= kGCDWebServerLogLevel_Debug) GCDLogMessage(kGCDWebServerLogLevel_Debug, __VA_ARGS__); } while (0)
+#define GWS_DNOT_REACHED() abort()
 
 #else
 
-#define DCHECK(__CONDITION__)
-#define DNOT_REACHED()
-#define LOG_DEBUG(...)
+#define GWS_DCHECK(__CONDITION__)
+#define GWS_DNOT_REACHED()
 
 #endif
 
 #endif
 
+/**
+ *  GCDWebServer internal constants and APIs.
+ */
+
 #define kGCDWebServerDefaultMimeType @"application/octet-stream"
 #define kGCDWebServerGCDQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
 #define kGCDWebServerErrorDomain @"GCDWebServerErrorDomain"

+ 11 - 11
GCDWebServer/Core/GCDWebServerRequest.m

@@ -95,12 +95,12 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
 }
 
 - (BOOL)writeData:(NSData*)data error:(NSError**)error {
-  DCHECK(!_finished);
+  GWS_DCHECK(!_finished);
   _stream.next_in = (Bytef*)data.bytes;
   _stream.avail_in = (uInt)data.length;
   NSMutableData* decodedData = [[NSMutableData alloc] initWithLength:kGZipInitialBufferSize];
   if (decodedData == nil) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     return NO;
   }
   NSUInteger length = 0;
@@ -130,7 +130,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
 }
 
 - (BOOL)close:(NSError**)error {
-  DCHECK(_finished);
+  GWS_DCHECK(_finished);
   inflateEnd(&_stream);
   return [super close:error];
 }
@@ -178,7 +178,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
     if (lengthHeader) {
       NSInteger length = [lengthHeader integerValue];
       if (_chunked || (length < 0)) {
-        DNOT_REACHED();
+        GWS_DNOT_REACHED();
         ARC_RELEASE(self);
         return nil;
       }
@@ -193,7 +193,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
       _length = NSUIntegerMax;
     } else {
       if (_type) {
-        DNOT_REACHED();
+        GWS_DNOT_REACHED();
         ARC_RELEASE(self);
         return nil;
       }
@@ -232,7 +232,7 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
         }
       }
       if ((_range.location == NSUIntegerMax) && (_range.length == 0)) {  // Ignore "Range" header if syntactically invalid
-        LOG_WARNING(@"Failed to parse 'Range' header \"%@\" for url: %@", rangeHeader, url);
+        GWS_LOG_WARNING(@"Failed to parse 'Range' header \"%@\" for url: %@", rangeHeader, url);
       }
     }
     
@@ -296,10 +296,10 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
 }
 
 - (BOOL)performOpen:(NSError**)error {
-  DCHECK(_type);
-  DCHECK(_writer);
+  GWS_DCHECK(_type);
+  GWS_DCHECK(_writer);
   if (_opened) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     return NO;
   }
   _opened = YES;
@@ -307,12 +307,12 @@ NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerReque
 }
 
 - (BOOL)performWriteData:(NSData*)data error:(NSError**)error {
-  DCHECK(_opened);
+  GWS_DCHECK(_opened);
   return [_writer writeData:data error:error];
 }
 
 - (BOOL)performClose:(NSError**)error {
-  DCHECK(_opened);
+  GWS_DCHECK(_opened);
   return [_writer close:error];
 }
 

+ 7 - 7
GCDWebServer/Core/GCDWebServerResponse.m

@@ -107,7 +107,7 @@
   } else {
     encodedData = [[NSMutableData alloc] initWithLength:kGZipInitialBufferSize];
     if (encodedData == nil) {
-      DNOT_REACHED();
+      GWS_DNOT_REACHED();
       return nil;
     }
     NSUInteger length = 0;
@@ -136,7 +136,7 @@
         }
         encodedData.length = 2 * encodedData.length;  // zlib has used all the output buffer so resize it and try again in case more data is available
       }
-      DCHECK(_stream.avail_in == 0);
+      GWS_DCHECK(_stream.avail_in == 0);
     } while (length == 0);  // Make sure we don't return an empty NSData if not in finished state
     encodedData.length = length;
   }
@@ -234,10 +234,10 @@
 }
 
 - (BOOL)performOpen:(NSError**)error {
-  DCHECK(_type);
-  DCHECK(_reader);
+  GWS_DCHECK(_type);
+  GWS_DCHECK(_reader);
   if (_opened) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     return NO;
   }
   _opened = YES;
@@ -245,12 +245,12 @@
 }
 
 - (NSData*)performReadData:(NSError**)error {
-  DCHECK(_opened);
+  GWS_DCHECK(_opened);
   return [_reader readData:error];
 }
 
 - (void)performClose {
-  DCHECK(_opened);
+  GWS_DCHECK(_opened);
   [_reader close];
 }
 

+ 2 - 2
GCDWebServer/Requests/GCDWebServerDataRequest.m

@@ -89,7 +89,7 @@
       NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
       _text = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
     } else {
-      DNOT_REACHED();
+      GWS_DNOT_REACHED();
     }
   }
   return _text;
@@ -101,7 +101,7 @@
     if ([mimeType isEqualToString:@"application/json"] || [mimeType isEqualToString:@"text/json"] || [mimeType isEqualToString:@"text/javascript"]) {
       _jsonObject = ARC_RETAIN([NSJSONSerialization JSONObjectWithData:_data options:0 error:NULL]);
     } else {
-      DNOT_REACHED();
+      GWS_DNOT_REACHED();
     }
   }
   return _jsonObject;

+ 15 - 15
GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m

@@ -171,22 +171,22 @@ static NSData* _dashNewlineData = nil;
 + (void)initialize {
   if (_newlineData == nil) {
     _newlineData = [[NSData alloc] initWithBytes:"\r\n" length:2];
-    DCHECK(_newlineData);
+    GWS_DCHECK(_newlineData);
   }
   if (_newlinesData == nil) {
     _newlinesData = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
-    DCHECK(_newlinesData);
+    GWS_DCHECK(_newlinesData);
   }
   if (_dashNewlineData == nil) {
     _dashNewlineData = [[NSData alloc] initWithBytes:"--\r\n" length:4];
-    DCHECK(_dashNewlineData);
+    GWS_DCHECK(_dashNewlineData);
   }
 }
 
 - (id)initWithBoundary:(NSString*)boundary defaultControlName:(NSString*)name arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files {
   NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
   if (data == nil) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     ARC_RELEASE(self);
     return nil;
   }
@@ -259,7 +259,7 @@ static NSData* _dashNewlineData = nil;
               }
             }
           } else {
-            DNOT_REACHED();
+            GWS_DNOT_REACHED();
           }
         }
         if (_contentType == nil) {
@@ -267,15 +267,15 @@ static NSData* _dashNewlineData = nil;
         }
         ARC_RELEASE(headers);
       } else {
-        LOG_ERROR(@"Failed decoding headers in part of 'multipart/form-data'");
-        DNOT_REACHED();
+        GWS_LOG_ERROR(@"Failed decoding headers in part of 'multipart/form-data'");
+        GWS_DNOT_REACHED();
       }
       if (_controlName) {
         if ([GCDWebServerTruncateHeaderValue(_contentType) isEqualToString:@"multipart/mixed"]) {
           NSString* boundary = GCDWebServerExtractHeaderValueParameter(_contentType, @"boundary");
           _subParser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:_controlName arguments:_arguments files:_files];
           if (_subParser == nil) {
-            DNOT_REACHED();
+            GWS_DNOT_REACHED();
             success = NO;
           }
         } else if (_fileName) {
@@ -284,12 +284,12 @@ static NSData* _dashNewlineData = nil;
           if (_tmpFile > 0) {
             _tmpPath = [path copy];
           } else {
-            DNOT_REACHED();
+            GWS_DNOT_REACHED();
             success = NO;
           }
         }
       } else {
-        DNOT_REACHED();
+        GWS_DNOT_REACHED();
         success = NO;
       }
       
@@ -311,7 +311,7 @@ static NSData* _dashNewlineData = nil;
           NSUInteger dataLength = range.location - 2;
           if (_subParser) {
             if (![_subParser appendBytes:dataBytes length:(dataLength + 2)] || ![_subParser isAtEnd]) {
-              DNOT_REACHED();
+              GWS_DNOT_REACHED();
               success = NO;
             }
             ARC_RELEASE(_subParser);
@@ -325,11 +325,11 @@ static NSData* _dashNewlineData = nil;
                 [_files addObject:file];
                 ARC_RELEASE(file);
               } else {
-                DNOT_REACHED();
+                GWS_DNOT_REACHED();
                 success = NO;
               }
             } else {
-              DNOT_REACHED();
+              GWS_DNOT_REACHED();
               success = NO;
             }
             ARC_RELEASE(_tmpPath);
@@ -359,7 +359,7 @@ static NSData* _dashNewlineData = nil;
           if ([_subParser appendBytes:_data.bytes length:length]) {
             [_data replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
           } else {
-            DNOT_REACHED();
+            GWS_DNOT_REACHED();
             success = NO;
           }
         } else if (_tmpPath) {
@@ -367,7 +367,7 @@ static NSData* _dashNewlineData = nil;
           if (result == (ssize_t)length) {
             [_data replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
           } else {
-            DNOT_REACHED();
+            GWS_DNOT_REACHED();
             success = NO;
           }
         }

+ 1 - 1
GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m

@@ -55,7 +55,7 @@
   NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
   NSString* string = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
   _arguments = ARC_RETAIN(GCDWebServerParseURLEncodedForm(string));
-  DCHECK(_arguments);
+  GWS_DCHECK(_arguments);
   ARC_RELEASE(string);
   
   return YES;

+ 3 - 3
GCDWebServer/Responses/GCDWebServerDataResponse.m

@@ -42,7 +42,7 @@
 
 - (instancetype)initWithData:(NSData*)data contentType:(NSString*)type {
   if (data == nil) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     ARC_RELEASE(self);
     return nil;
   }
@@ -107,7 +107,7 @@
 - (instancetype)initWithText:(NSString*)text {
   NSData* data = [text dataUsingEncoding:NSUTF8StringEncoding];
   if (data == nil) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     ARC_RELEASE(self);
     return nil;
   }
@@ -117,7 +117,7 @@
 - (instancetype)initWithHTML:(NSString*)html {
   NSData* data = [html dataUsingEncoding:NSUTF8StringEncoding];
   if (data == nil) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     ARC_RELEASE(self);
     return nil;
   }

+ 8 - 8
GCDWebServer/Responses/GCDWebServerErrorResponse.m

@@ -34,7 +34,7 @@
 @implementation GCDWebServerErrorResponse
 
 + (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+  GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
   va_list arguments;
   va_start(arguments, format);
   GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments]);
@@ -43,7 +43,7 @@
 }
 
 + (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+  GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
   va_list arguments;
   va_start(arguments, format);
   GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments]);
@@ -52,7 +52,7 @@
 }
 
 + (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+  GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
   va_list arguments;
   va_start(arguments, format);
   GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments]);
@@ -61,7 +61,7 @@
 }
 
 + (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+  GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
   va_list arguments;
   va_start(arguments, format);
   GCDWebServerErrorResponse* response = ARC_AUTORELEASE([[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments]);
@@ -87,7 +87,7 @@ static inline NSString* _EscapeHTMLString(NSString* string) {
 }
 
 - (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+  GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
   va_list arguments;
   va_start(arguments, format);
   self = [self initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
@@ -96,7 +96,7 @@ static inline NSString* _EscapeHTMLString(NSString* string) {
 }
 
 - (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+  GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
   va_list arguments;
   va_start(arguments, format);
   self = [self initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
@@ -105,7 +105,7 @@ static inline NSString* _EscapeHTMLString(NSString* string) {
 }
 
 - (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+  GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
   va_list arguments;
   va_start(arguments, format);
   self = [self initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
@@ -114,7 +114,7 @@ static inline NSString* _EscapeHTMLString(NSString* string) {
 }
 
 - (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
-  DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+  GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
   va_list arguments;
   va_start(arguments, format);
   self = [self initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];

+ 4 - 4
GCDWebServer/Responses/GCDWebServerFileResponse.m

@@ -77,13 +77,13 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
 - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
   struct stat info;
   if (lstat([path fileSystemRepresentation], &info) || !(info.st_mode & S_IFREG)) {
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     ARC_RELEASE(self);
     return nil;
   }
 #ifndef __LP64__
   if (info.st_size >= (off_t)4294967295) {  // In 32 bit mode, we can't handle files greater than 4 GiBs (don't use "NSUIntegerMax" here to avoid potential unsigned to signed conversion issues)
-    DNOT_REACHED();
+    GWS_DNOT_REACHED();
     ARC_RELEASE(self);
     return nil;
   }
@@ -115,7 +115,7 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
     if (hasByteRange) {
       [self setStatusCode:kGCDWebServerHTTPStatusCode_PartialContent];
       [self setValue:[NSString stringWithFormat:@"bytes %lu-%lu/%lu", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), (unsigned long)fileSize] forAdditionalHeader:@"Content-Range"];
-      LOG_DEBUG(@"Using content bytes range [%lu-%lu] for file \"%@\"", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), path);
+      GWS_LOG_DEBUG(@"Using content bytes range [%lu-%lu] for file \"%@\"", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), path);
     }
     
     if (attachment) {
@@ -127,7 +127,7 @@ static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
         [self setValue:value forAdditionalHeader:@"Content-Disposition"];
         ARC_RELEASE(lossyFileName);
       } else {
-        DNOT_REACHED();
+        GWS_DNOT_REACHED();
       }
     }
     

+ 7 - 17
README.md

@@ -5,7 +5,7 @@ Overview
 [![Version](http://cocoapod-badges.herokuapp.com/v/GCDWebServer/badge.png)](http://cocoadocs.org/docsets/GCDWebServer)
 [![Platform](http://cocoapod-badges.herokuapp.com/p/GCDWebServer/badge.png)](http://cocoadocs.org/docsets/GCDWebServer)
 
-*ANNOUNCEMENT: If you like GCDWebServer, check out [XLFacility](https://github.com/swisspol/XLFacility), an elegant and powerful logging facility for OS X & iOS by the same author and also open-source. XLFacility can be used seemlessly to handle logging from GCDWebServer (see "Custom Logging" below).*
+*ANNOUNCEMENT: If you like GCDWebServer, check out [XLFacility](https://github.com/swisspol/XLFacility), an elegant and powerful logging facility for OS X & iOS by the same author and also open-source. XLFacility can be used seemlessly to handle logging from GCDWebServer (see "Logging in GCDWebServer" below).*
 
 GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in OS X & iOS apps. It was written from scratch with the following goals in mind:
 * Elegant and easy to use architecture with only 4 core classes: server, connection, request and response (see "Understanding GCDWebServer's Architecture" below)
@@ -302,26 +302,16 @@ Fortunately, GCDWebServer does all of this automatically for you:
 
 HTTP connections are often initiated in batches (or bursts), for instance when loading a web page with multiple resources. This makes it difficult to accurately detect when the *very last* HTTP connection has been closed: it's possible 2 consecutive HTTP connections part of the same batch would be separated by a small delay instead of overlapping. It would be bad for the client if GCDWebServer suspended itself right in between. The ```GCDWebServerOption_ConnectedStateCoalescingInterval``` option solves this problem elegantly by forcing GCDWebServer to wait some extra delay before performing any action after the last HTTP connection has been closed, just in case a new HTTP connection is initiated within this delay.
 
-Debug Builds & Custom Logging
-=============================
+Logging in GCDWebServer
+=======================
 
-When building GCDWebServer in "Debug" mode versus "Release" mode, GCDWebServer logs a lot more information and also performs a number of internal consistency checks. To enable this behavior, define the preprocessor constant ```DEBUG=1``` when compiling GCDWebServer. In Xcode target settings, this can be done by adding ```DEBUG=1``` to the build setting ```GCC_PREPROCESSOR_DEFINITIONS``` when building in "Debug" configuration.
+Both for debugging and informational purpose, GCDWebServer log messages extensively whenever something happens. Furthermore, when building GCDWebServer in "Debug" mode versus "Release" mode, it logs even more information but also performs a number of internal consistency checks. To enable this behavior, define the preprocessor constant ```DEBUG=1``` when compiling GCDWebServer. In Xcode target settings, this can be done by adding ```DEBUG=1``` to the build setting ```GCC_PREPROCESSOR_DEFINITIONS``` when building in "Debug" configuration. You can also control the logging verbosity at run time by calling ```+[GCDWebServer setLogLevel:]```.
 
-It's also possible to replace the logging system used by GCDWebServer by a custom one. Simply define the preprocessor constant ```__GCDWEBSERVER_LOGGING_HEADER__``` to the name of a header file (e.g. "MyLogging.h") that defines these macros:
+By default all messages logged by GCDWebServer are sent to its built-in logging facility, which simply outputs to ```stderr``` assuming a terminal type device is connected. In order to better integrate with the rest of your app or because of the amount of information logged, you might want to use another logging facility.
 
-```
-#define LOG_DEBUG(...)  // Should not do anything unless the preprocessor constant DEBUG is non-zero
-#define LOG_VERBOSE(...)
-#define LOG_INFO(...)
-#define LOG_WARNING(...)
-#define LOG_ERROR(...)
-#define LOG_EXCEPTION(__EXCEPTION__)
-
-#define DCHECK(__CONDITION__)  // Should not do anything unless the preprocessor constant DEBUG is non-zero
-#define DNOT_REACHED()  // Should not do anything unless the preprocessor constant DEBUG is non-zero
-```
+GCDWebServer has automatic support for [XLFacility](https://github.com/swisspol/XLFacility) (by the same author as GCDWebServer and also open-source) and [CocoaLumberjack](https://github.com/CocoaLumberjack/CocoaLumberjack). If either of them is in the same Xcode project, GCDWebServer should use it automatically instead of the built-in logging facility (see [GCDWebServerPrivate.h](GCDWebServer/Core/GCDWebServerPrivate.h) for the implementation details).
 
-GCDWebServer comes with [an example of such header file](XLFacilityLogging.h) that allows to use [XLFacility](https://github.com/swisspol/XLFacility) as the logging system.
+*It's also possible to use a custom logging facility - see [GCDWebServer.h](GCDWebServer/Core/GCDWebServer.h) for more information.*
 
 Advanced Example 1: Implementing HTTP Redirects
 ===============================================

+ 0 - 50
XLFacilityLogging.h

@@ -1,50 +0,0 @@
-/*
- Copyright (c) 2012-2014, Pierre-Olivier Latour
- All rights reserved.
- 
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * The name of Pierre-Olivier Latour may not be used to endorse
- or promote products derived from this software without specific
- prior written permission.
- 
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "XLFacilityMacros.h"
-
-/**
- *  This header file allows to use XLFacility logging system with GCDWebServer:
- *  https://github.com/swisspol/XLFacility
- *
- *  To use, first add this header file to your Xcode project then add a new
- *  build setting "GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS" with this
- *  value:
- *
- *  __GCDWEBSERVER_LOGGING_HEADER__=\"XLFacilityLogging.h\"
- *
- */
-
-#define LOG_DEBUG(...) XLOG_DEBUG(__VA_ARGS__)
-#define LOG_VERBOSE(...) XLOG_VERBOSE(__VA_ARGS__)
-#define LOG_INFO(...) XLOG_INFO(__VA_ARGS__)
-#define LOG_WARNING(...) XLOG_WARNING(__VA_ARGS__)
-#define LOG_ERROR(...) XLOG_ERROR(__VA_ARGS__)
-#define LOG_EXCEPTION(__EXCEPTION__) XLOG_EXCEPTION(__EXCEPTION__)
-
-#define DCHECK(__CONDITION__) XLOG_DEBUG_CHECK(__CONDITION__)
-#define DNOT_REACHED() XLOG_DEBUG_UNREACHABLE()