public
Description: A cross-platform web server that's scripted with Nu.
Homepage: http://programming.nu
Clone URL: git://github.com/timburks/nunja.git
Some small cleanup to dns and http request handling.
timburks (author)
Thu May 08 17:24:10 -0700 2008
commit  d20db0609e3e5a3ebf02be8290966718cfc8c9aa
tree    51e3e9fa7a54ddd9e9f44190b73ce4abdab12391
parent  f635b744dd371076b926a6cc1dae1b00158bca22
...
161
162
163
164
165
166
 
167
168
169
...
161
162
163
 
 
 
164
165
166
167
0
@@ -161,9 +161,7 @@
0
             (then (set BODY (eval @statements))) ;; deprecated, evaluates statements in the instance method context
0
             (else (set BODY (@statements @match request response)))) ;; new style, evaluates a function with a lexical closure
0
         
0
- (unless BODY
0
- (puts "returning early, leaving connection open")
0
- (return))
0
+ (unless BODY (return)) ;; return early and leave connection open, this expects the handler to have created a closure
0
         
0
         (if (BODY isKindOfClass:NSString)
0
             (then (set html "<head>\n")
0
...
51
52
53
54
55
56
57
...
51
52
53
 
54
55
56
0
@@ -51,7 +51,6 @@
0
        (set argi (+ argi 1)))
0
 
0
 (set n ((Nunja alloc) init))
0
-(set $nunja n)
0
 (n bindToAddress:"0.0.0.0" port:port)
0
 (if site
0
     (n setDelegate:((NunjaDelegate alloc) initWithSite:site)))
...
28
29
30
 
 
 
 
 
 
 
 
 
 
 
31
32
33
34
 
35
36
37
...
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
...
163
164
165
166
167
168
169
170
 
171
172
173
...
195
196
197
198
 
199
200
201
...
250
251
252
253
254
255
256
257
258
259
 
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
 
 
 
 
 
 
297
298
299
...
302
303
304
305
306
 
307
308
 
309
310
311
 
312
313
314
 
315
316
317
...
321
322
323
 
 
324
325
326
327
328
329
 
 
330
331
332
 
 
 
 
333
334
335
336
337
338
339
340
341
 
 
342
343
 
344
345
346
...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
...
51
52
53
 
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 
 
 
 
 
 
 
 
 
69
70
71
...
169
170
171
 
 
172
173
 
174
175
176
177
...
199
200
201
 
202
203
204
205
...
254
255
256
 
257
258
 
259
 
 
260
261
 
262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
290
291
292
293
294
295
296
297
298
...
301
302
303
 
 
304
305
 
306
307
308
 
309
310
311
 
312
313
314
315
...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
 
 
 
 
 
 
 
341
342
343
 
344
345
346
347
0
@@ -28,10 +28,22 @@ limitations under the License.
0
 #import <Foundation/Foundation.h>
0
 #import <Nu/Nu.h>
0
 
0
+void NunjaInit()
0
+{
0
+ static initialized = 0;
0
+ if (!initialized) {
0
+ initialized = 1;
0
+ [Nu loadNuFile:@"nunja" fromBundleWithIdentifier:@"nu.programming.nunja" withContext:nil];
0
+ }
0
+}
0
+
0
+@class Nunja;
0
+
0
 static bool verbose_nunja = false;
0
 
0
 @interface NunjaRequest : NSObject
0
 {
0
+ Nunja *nunja;
0
     struct evhttp_request *req;
0
 }
0
 
0
@@ -39,27 +51,21 @@ static bool verbose_nunja = false;
0
 
0
 @implementation NunjaRequest
0
 
0
-- (id) initWithRequest:(struct evhttp_request *)r
0
+- (id) initWithNunja:(Nunja *)n request:(struct evhttp_request *)r
0
 {
0
     [super init];
0
+ nunja = n;
0
     req = r;
0
     return self;
0
 }
0
 
0
+- (Nunja *) nunja {return nunja;}
0
+
0
 - (NSString *) uri
0
 {
0
     return [NSString stringWithCString:evhttp_request_uri(req) encoding:NSUTF8StringEncoding];
0
 }
0
 
0
-void NunjaInit()
0
-{
0
- static initialized = 0;
0
- if (!initialized) {
0
- initialized = 1;
0
- [Nu loadNuFile:@"nunja" fromBundleWithIdentifier:@"nu.programming.nunja" withContext:nil];
0
- }
0
-}
0
-
0
 - (NSData *) body
0
 {
0
     if (!req->input_buffer->buffer)
0
@@ -163,11 +169,9 @@ static void nunja_response_helper(struct evhttp_request *req, int code, NSString
0
 - (void) handleRequest:(NunjaRequest *)request;
0
 @end
0
 
0
-struct event_base *event_base;
0
-
0
 @interface Nunja : NSObject
0
 {
0
-
0
+ struct event_base *event_base;
0
     struct evhttp *httpd;
0
     id<NSObject,NunjaDelegate> delegate;
0
 }
0
@@ -195,7 +199,7 @@ static void nunja_request_handler(struct evhttp_request *req, void *nunja_pointe
0
 
0
     id delegate = [nunja delegate];
0
     if (delegate) {
0
- [delegate handleRequest:[[[NunjaRequest alloc] initWithRequest:req] autorelease]];
0
+ [delegate handleRequest:[[[NunjaRequest alloc] initWithNunja:nunja request:req] autorelease]];
0
     }
0
     else {
0
         nunja_response_helper(req, HTTP_OK, @"OK",
0
@@ -250,50 +254,45 @@ static void nunja_request_handler(struct evhttp_request *req, void *nunja_pointe
0
 static void nunja_dns_gethostbyname_cb(int result, char type, int count, int ttl, void *addresses, void *arg)
0
 {
0
     id address = nil;
0
-
0
     if (result == DNS_ERR_TIMEOUT) {
0
         fprintf(stdout, "[Timed out] ");
0
- goto out;
0
     }
0
-
0
- if (result != DNS_ERR_NONE) {
0
+ else if (result != DNS_ERR_NONE) {
0
         fprintf(stdout, "[Error code %d] ", result);
0
- goto out;
0
     }
0
-
0
- fprintf(stderr, "type: %d, count: %d, ttl: %d: ", type, count, ttl);
0
-
0
- switch (type) {
0
- case DNS_IPv4_A:
0
- {
0
- struct in_addr *in_addrs = addresses;
0
- int i;
0
- /* a resolution that's not valid does not help */
0
- if (ttl < 0)
0
- goto out;
0
- if (count == 0)
0
- goto out;
0
- address = [NSString stringWithFormat:@"%s", inet_ntoa(in_addrs[0])];
0
- break;
0
+ else {
0
+ fprintf(stdout, "type: %d, count: %d, ttl: %d\n", type, count, ttl);
0
+ switch (type) {
0
+ case DNS_IPv4_A:
0
+ {
0
+ struct in_addr *in_addrs = addresses;
0
+ if (ttl < 0) {
0
+ // invalid resolution
0
+ }
0
+ else if (count == 0) {
0
+ // no addresses
0
+ }
0
+ else {
0
+ address = [NSString stringWithFormat:@"%s", inet_ntoa(in_addrs[0])];
0
+ }
0
+ break;
0
+ }
0
+ case DNS_PTR:
0
+ /* may get at most one PTR */
0
+ // this needs review. TB.
0
+ if (count == 1)
0
+ fprintf(stdout, "addresses: %s ", *(char **)addresses);
0
+ break;
0
+ default:
0
+ break;
0
         }
0
- case DNS_PTR:
0
- /* may get at most one PTR */
0
- if (count != 1)
0
- goto out;
0
-
0
- fprintf(stderr, "%s ", *(char **)addresses);
0
- break;
0
- default:
0
- goto out;
0
- }
0
- out:
0
- {
0
- NuBlock *block = (NuBlock *) arg;
0
- NuCell *args = [[NuCell alloc] init];
0
- [args setCar:address];
0
- [block evalWithArguments:args context:nil];
0
- [block release];
0
     }
0
+ NuBlock *block = (NuBlock *) arg;
0
+ NuCell *args = [[NuCell alloc] init];
0
+ [args setCar:address];
0
+ [block evalWithArguments:args context:nil];
0
+ [block release];
0
+ [args release];
0
 }
0
 
0
 - (void) resolveDomainName:(NSString *) name andDo:(NuBlock *) block
0
@@ -302,16 +301,15 @@ static void nunja_dns_gethostbyname_cb(int result, char type, int count, int ttl
0
     evdns_resolve_ipv4([name cStringUsingEncoding:NSUTF8StringEncoding], 0, nunja_dns_gethostbyname_cb, block);
0
 }
0
 
0
-void
0
-nu_http_request_done(struct evhttp_request *req, void *arg)
0
+void nunja_http_request_done(struct evhttp_request *req, void *arg)
0
 {
0
- printf("received %d\n", (int) arg);
0
+ fprintf(stdout, "received %d bytes\n", (int) arg);
0
     NSData *data = nil;
0
     if (req->response_code != HTTP_OK) {
0
- fprintf(stderr, "FAILED to get OK\n");
0
+ fprintf(stdout, "FAILED to get OK\n");
0
     }
0
     else if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
0
- fprintf(stderr, "FAILED to find Content-Type\n");
0
+ fprintf(stdout, "FAILED to find Content-Type\n");
0
     }
0
     else {
0
         data = [NSData dataWithBytes:EVBUFFER_DATA(req->input_buffer) length:EVBUFFER_LENGTH(req->input_buffer)];
0
@@ -321,26 +319,29 @@ nu_http_request_done(struct evhttp_request *req, void *arg)
0
     [args setCar:data];
0
     [block evalWithArguments:args context:nil];
0
     [block release];
0
+ [args release];
0
+ fprintf(stdout, "end of callback\n");
0
     // leaking...
0
     //evhttp_connection_free(req->evcon);
0
 }
0
 
0
 - (void) getResourceFromHost:(NSString *) host address:(NSString *) address port:(int)port path:(NSString *)path andDo:(NuBlock *) block
0
 {
0
+ [block retain];
0
+ // make the connection
0
     struct evhttp_connection *evcon = evhttp_connection_new([address cStringUsingEncoding:NSUTF8StringEncoding], port);
0
     if (evcon == NULL) {
0
         fprintf(stdout, "FAILED to connect\n");
0
+ NuCell *args = [[NuCell alloc] init];
0
+ [block evalWithArguments:args context:nil];
0
+ [block release];
0
+ [args release];
0
         return;
0
     }
0
- /*
0
- * At this point, we want to schedule a request to the HTTP
0
- * server using our make request method.
0
- */
0
- [block retain];
0
- struct evhttp_request *req = evhttp_request_new(nu_http_request_done, block);
0
- /* Add the information that we care about */
0
+ // make the request
0
+ struct evhttp_request *req = evhttp_request_new(nunja_http_request_done, block);
0
     evhttp_add_header(req->output_headers, "Host", [host cStringUsingEncoding:NSUTF8StringEncoding]);
0
- /* We give ownership of the request to the connection */
0
+ // give ownership of the request to the connection
0
     if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, [path cStringUsingEncoding:NSUTF8StringEncoding]) == -1) {
0
         fprintf(stdout, "FAILED to make the request \n");
0
     }
...
154
155
156
 
 
157
158
159
160
161
162
163
164
165
166
167
 
 
 
 
 
 
 
 
 
 
168
169
170
171
172
173
174
175
176
177
178
179
180
181
 
 
 
 
 
 
 
 
 
 
182
183
...
154
155
156
157
158
159
 
160
 
 
 
 
 
 
 
 
161
162
163
164
165
166
167
168
169
170
171
 
172
173
 
 
 
 
 
 
 
 
 
 
174
175
176
177
178
179
180
181
182
183
184
185
0
@@ -154,30 +154,32 @@ END)
0
                         else (size doubleValue)))
0
      (set data (NSData dataWithSize:(* megabytes 1024 1024))))
0
 
0
+;; perform a dns lookup
0
+;; ex: /dns/programming.nu
0
 (get (regex -"/dns/(.*)")
0
- (puts (REQUEST description))
0
      (set hostname (MATCH groupAtIndex:1))
0
- ($nunja resolveDomainName:hostname andDo:
0
- (do (address)
0
- (if address
0
- (REQUEST respondWithString:"resolved #{hostname} as #{address}")
0
- else
0
- (REQUEST respondWithString:"unable to resolve #{hostname}"))))
0
- nil)
0
-
0
+ ((REQUEST nunja) resolveDomainName:hostname andDo:
0
+ (do (address)
0
+ (if address
0
+ (REQUEST respondWithString:"resolved #{hostname} as #{address}")
0
+ else
0
+ (REQUEST respondWithString:"unable to resolve #{hostname}"))))
0
+ nil) ;; return nil to leave the connection open
0
+
0
+;; request and return a resource from a specified host
0
+;; ex: /proxy/programming.nu/about
0
 (get (regex -"/proxy/([^\/]+)/(.*)")
0
- (puts (REQUEST description))
0
      (set host (MATCH groupAtIndex:1))
0
      (set path (+ "/" (MATCH groupAtIndex:2)))
0
- ($nunja resolveDomainName:host andDo:
0
- (do (address)
0
- (if address
0
- (then ($nunja getResourceFromHost:host address:address port:80 path:path andDo:
0
- (do (data)
0
- (if data
0
- (then (REQUEST respondWithData:data))
0
- (else (REQUEST respondWithString:"unable to load #{path}"))))))
0
- (else (REQUEST respondWithString:"unable to resolve host #{host}")))))
0
- nil)
0
+ ((REQUEST nunja) resolveDomainName:host andDo:
0
+ (do (address)
0
+ (if address
0
+ (then ((REQUEST nunja) getResourceFromHost:host address:address port:80 path:path andDo:
0
+ (do (data)
0
+ (if data
0
+ (then (REQUEST respondWithData:data))
0
+ (else (REQUEST respondWithString:"unable to load #{path}"))))))
0
+ (else (REQUEST respondWithString:"unable to resolve host #{host}")))))
0
+ nil) ;; return nil to leave the connection open
0
 
0
 

Comments

    No one has commented yet.