-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathHandler.m
176 lines (157 loc) · 4.53 KB
/
Handler.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* Handler.m: An example Objective-C web server
*
* Copyright (C) 2016 Niels Grewe
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#import "Handler.h"
#import <WebServer/WebServer.h>
#import <Foundation/NSLocale.h>
#include <dispatch/dispatch.h>
static NSString* kWSHandlerDomain = @"WebServerHandlerDomain";
static NSDateFormatter *_formatter;
#define STR_DATE(x) [_formatter stringFromDate: x]
#define STR_NOW STR_DATE([NSDate date])
@interface Handler (WebServerDelegate) <WebServerDelegate>
@end
@implementation Handler
{
WebServer* server;
BOOL _done;
}
@dynamic done;
+ (void)initialize
{
if (self == [Handler class])
{
_formatter = [[NSDateFormatter alloc] init];
NSLocale *posix =
[[NSLocale alloc] initWithLocaleIdentifier: @"en_US_POSIX"];
[_formatter setLocale: posix];
[_formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];
}
}
- (BOOL)isDone
{
if (_done)
{
return YES;
}
if (_quitting)
{
if ([[server connections] count] > 0)
{
return NO;
}
_done = YES;
_quitting = NO;
return YES;
}
return _done;
}
- (void)_failWithErrorCode: (NSInteger)code
description: (NSString*)desc
{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
desc, NSLocalizedDescriptionKey, nil];
_error = [NSError errorWithDomain: kWSHandlerDomain
code: code
userInfo: dict];
_done = YES;
}
- (id)init
{
if (nil == (self = [super init]))
{
return nil;
}
server = [WebServer new];
/*
* We read the configuration parameters from the user defaults, which include
* command line parameters.
*/
NSUserDefaults *dflts = [NSUserDefaults standardUserDefaults];
NSString *port = [dflts stringForKey: @"Port"];
if (([port integerValue] <= 0) || ([port integerValue] > 65535))
{
[self _failWithErrorCode: 3
description:
[NSString stringWithFormat: @"Invalid port (%@)", port]];
return self;
}
if (NO == [server setPort: port secure: nil])
{
[self _failWithErrorCode: 4
description:
[NSString stringWithFormat: @"Could not listen on port %@", port]];
return self;
}
[server setVerbose: [dflts boolForKey: @"Debug"]];
[server setDelegate: self];
return self;
}
- (void)quit
{
/*
* Removing the connection parameters causes the server to no longer accept
* new connections.
*/
[server setAddress: nil port: nil secure: nil];
_quitting = YES;
}
- (BOOL) processRequest: (WebServerRequest*)request
response: (WebServerResponse*)response
for: (WebServer*)http
{
/* This is the actual workhorse method. If we do all our processing here,
* we can just return YES and effectively handle the request synchronously.
* But that is terribly boring. So we put the processing onto a dispatch
* queue and return NO to indicate that it's being done asynchronously.
*/
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
GSRegisterCurrentThread();
NSString *method = [[request headerNamed: @"x-http-method"] value];
if ([method caseInsensitiveCompare: @"GET"] == NSOrderedSame)
{
[response setContent: @"Hello world!"
type: @"text/plain"];
[response setHeader: @"http"
value: @"HTTP/1.1 200 OK"
parameters: nil];
}
else
{
[response setContent: @"Method not allowed"
type: @"text/plain"];
[response setHeader: @"http"
value: @"HTTP/1.0 405 Method Not Allowed"
parameters: nil];
}
// After we are done processing the request, hand it back to the server
[http completedWithResponse: response];
GSUnregisterCurrentThread();
});
/* Return value no indicates that we are processing asynchronously */
return NO;
}
- (void) _log: (NSString*)message level: (NSString*)level
{
GSPrintf(stdout, @"%@/%@ %@ -- %@\n", level, NSStringFromClass([self class]),
STR_NOW, message);
}
- (void) webAlert: (NSString*)message for: (WebServer*)http
{
[self _log: message level: @"W"];
}
- (void) webAudit: (NSString*)message for: (WebServer*)http
{
GSPrintf(stdout, @"%@\n", message);
}
- (void) webLog: (NSString*)message for: (WebServer*)http
{
[self _log: message level: @"D"];
}
@end