1313
1414@implementation MyHTTPConnection
1515
16+ static NSMutableSet *webSocketLoggers;
17+
18+ /* *
19+ * The runtime sends initialize to each class in a program exactly one time just before the class,
20+ * or any class that inherits from it, is sent its first message from within the program. (Thus the
21+ * method may never be invoked if the class is not used.) The runtime sends the initialize message to
22+ * classes in a thread-safe manner. Superclasses receive this message before their subclasses.
23+ *
24+ * This method may also be called directly (assumably by accident), hence the safety mechanism.
25+ **/
26+ + (void )initialize
27+ {
28+ static dispatch_once_t onceToken;
29+ dispatch_once (&onceToken, ^{
30+
31+ // We need some place to store the webSocketLogger instances.
32+ // So we'll store them here, in a class variable.
33+ //
34+ // We'll also use a simple notification system to release them when they die.
35+
36+ webSocketLoggers = [[NSMutableSet alloc ] init ];
37+
38+ [[NSNotificationCenter defaultCenter ] addObserver: self
39+ selector: @selector (webSocketLoggerDidDie: )
40+ name: WebSocketLoggerDidDieNotification
41+ object: nil ];
42+ });
43+ }
44+
45+ + (void )addWebSocketLogger : (WebSocketLogger *)webSocketLogger
46+ {
47+ @synchronized (webSocketLoggers)
48+ {
49+ [webSocketLoggers addObject: webSocketLogger];
50+ }
51+ }
52+
53+ + (void )webSocketLoggerDidDie : (NSNotification *)notification
54+ {
55+ @synchronized (webSocketLoggers)
56+ {
57+ [webSocketLoggers removeObject: [notification object ]];
58+ }
59+ }
60+
61+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
62+ #pragma mark Utilities
63+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
64+
65+ /* *
66+ * Returns the logFileManager, which is a part of the DDFileLogger system.
67+ * The DDLogFileManager is the subsystem which manages the location and creation of log files.
68+ **/
1669- (id <DDLogFileManager>)logFileManager
1770{
1871 WebServerIPhoneAppDelegate *appDelegate;
@@ -21,6 +74,38 @@ @implementation MyHTTPConnection
2174 return appDelegate.fileLogger .logFileManager ;
2275}
2376
77+ /* *
78+ * Dynamic discovery of proper websocket href.
79+ **/
80+ - (NSString *)wsLocation
81+ {
82+ NSString *port = [NSString stringWithFormat: @" %hu " , [asyncSocket localPort ]];
83+
84+ NSString *wsLocation;
85+ NSString *wsHost = [request headerField: @" Host" ];
86+
87+ if (wsHost == nil )
88+ {
89+ wsLocation = [NSString stringWithFormat: @" ws://localhost:%@ /livelog" , port];
90+ }
91+ else
92+ {
93+ wsLocation = [NSString stringWithFormat: @" ws://%@ /livelog" , wsHost];
94+ }
95+
96+ return wsLocation;
97+ }
98+
99+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100+ #pragma mark /logs.html
101+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102+
103+ /* *
104+ * Returns the response body for requests to "/logs/index.html".
105+ *
106+ * The response is generated dynamically.
107+ * It returns the list of log files currently on the system, along with their creation date and file size.
108+ **/
24109- (NSData *)generateIndexData
25110{
26111 NSArray *sortedLogFileInfos = [[self logFileManager ] sortedLogFileInfos ];
@@ -83,40 +168,37 @@ - (NSData *)generateIndexData
83168 return [response dataUsingEncoding: NSUTF8StringEncoding];
84169}
85170
86- - (NSString *)filePathForURI : (NSString *)path
171+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172+ #pragma mark HTTPConnection
173+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
174+
175+ /* *
176+ * Overrides method in HTTPConnection.
177+ *
178+ * This method is invoked to retrieve the filePath for a given URI.
179+ * We override it to provide proper mapping for log file paths.
180+ **/
181+ - (NSString *)filePathForURI : (NSString *)path allowDirectory : (BOOL )allowDirectory
87182{
88183 if ([path hasPrefix: @" /logs/" ])
89184 {
90185 NSString *logsDir = [[self logFileManager ] logsDirectory ];
91186 return [logsDir stringByAppendingPathComponent: [path lastPathComponent ]];
92187 }
93188
94- return [super filePathForURI: path];
95- }
96-
97- - (NSString *)wsLocation
98- {
99- NSString *port = [NSString stringWithFormat: @" %hu " , [asyncSocket localPort ]];
100-
101- NSString *wsLocation;
102- NSString *wsHost = [request headerField: @" Host" ];
103-
104- if (wsHost == nil )
105- {
106- wsLocation = [NSString stringWithFormat: @" ws://localhost:%@ /livelog" , port];
107- }
108- else
109- {
110- wsLocation = [NSString stringWithFormat: @" ws://%@ /livelog" , wsHost];
111- }
112-
113- return wsLocation;
189+ // Fall through
190+ return [super filePathForURI: path allowDirectory: allowDirectory];
114191}
115192
193+ /* *
194+ * Overrides method in HTTPConnection.
195+ **/
116196- (NSObject <HTTPResponse> *)httpResponseForMethod : (NSString *)method URI : (NSString *)path
117197{
118198 if ([path isEqualToString: @" /logs.html" ])
119199 {
200+ // Dynamically generate html response with list of available log files
201+
120202 NSData *indexData = [self generateIndexData ];
121203 return [[HTTPDataResponse alloc ] initWithData: indexData];
122204 }
@@ -139,30 +221,26 @@ - (NSString *)wsLocation
139221 separator: @" %% "
140222 replacementDictionary: replacementDict];
141223 }
142- else
143- {
144- return [super httpResponseForMethod: method URI: path];
145- }
224+
225+ // Fall through
226+ return [super httpResponseForMethod: method URI: path];
146227}
147228
229+ /* *
230+ * Overrides method in HTTPConnection.
231+ **/
148232- (WebSocket *)webSocketForURI : (NSString *)path
149233{
150234 if ([path isEqualToString: @" /livelog" ])
151235 {
152236 // Create the WebSocket
153- WebSocket *ws = [[WebSocket alloc ] initWithRequest: request socket: asyncSocket];
237+ WebSocket *webSocket = [[WebSocket alloc ] initWithRequest: request socket: asyncSocket];
154238
155239 // Create the WebSocketLogger
156- WebSocketLogger *wsLogger = [[WebSocketLogger alloc ] initWithWebSocket: ws];
157-
158- // Todo - Broken under ARC. Needs a fix. Commens below from pre-arc.
159- //
160- // Memory management:
161- // The WebSocket will be retained by the HTTPServer and the WebSocketLogger.
162- // The WebSocketLogger will be retained by the logging framework,
163- // as it adds itself to the list of active loggers from within its init method.
240+ WebSocketLogger *webSocketLogger = [[WebSocketLogger alloc ] initWithWebSocket: webSocket];
164241
165- return ws;
242+ [[self class ] addWebSocketLogger: webSocketLogger];
243+ return webSocket;
166244 }
167245
168246 return [super webSocketForURI: path];
0 commit comments