Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

428 lines (382 sloc) 12.642 kB
/*
** mod_nu.c -- Apache sample nu module
** [Autogenerated via ``apxs -n nu -g'']
**
** To play with this sample module first compile it into a
** DSO file and install it into Apache's modules directory
** by running:
**
** $ apxs -c -i mod_nu.c
**
** Then activate it in Apache's httpd.conf file for instance
** for the URL /nu in as follows:
**
** # httpd.conf
** LoadModule nu_module modules/mod_nu.so
** <Location /nu>
** SetHandler nu
** </Location>
**
** Then after restarting Apache via
**
** $ apachectl restart
**
** you immediately can request the URL /nu and watch for the
** output of this module. This can be achieved for instance via:
**
** $ lynx -mime_header http://localhost/nu
**
** The output should be similar to the following one:
**
** HTTP/1.1 200 OK
** Date: Tue, 31 Mar 1998 14:42:22 GMT
** Server: Apache/1.3.4 (Unix)
** Connection: close
** Content-Type: text/html
**
** The sample page from mod_nu.c
*/
#import <Foundation/Foundation.h>
#import <Nu/Nu.h>
#include "httpd.h"
#include "http_log.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
@interface ApacheRequest : NSObject {
request_rec *request;
}
@end
NSString *stringWithCString(char *cString) {
if (cString) {
return [NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
} else {
return nil;
}
}
int extract_table_entry(void *rec, const char *key, const char *value) {
[((NSMutableDictionary *) rec) setObject:stringWithCString(value) forKey:stringWithCString(key)];
return 1;
}
NSMutableDictionary *dictionaryFromTable(apr_table_t *table) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
apr_table_do(&extract_table_entry, (void *)dict, table, NULL);
return dict;
}
@implementation ApacheRequest
- (void) setRequest:(request_rec *) r {request = r;}
- (NSString *) unparsed_uri {return stringWithCString(request->unparsed_uri);}
- (NSString *) uri {return stringWithCString(request->uri);}
- (NSString *) filename {return stringWithCString(request->filename);}
- (NSString *) path_info {return stringWithCString(request->path_info);}
- (NSString *) args {return stringWithCString(request->args);}
// this isn't quite right -- apache tables can have multiple entries per key.
- (NSMutableDictionary *) headers {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
apr_table_do(&extract_table_entry, (void *)dict, request->headers_in, NULL);
return dict;
}
@end
typedef struct {
char *string;
} modnu_config;
module AP_MODULE_DECLARE_DATA nu_module;
int read_post_body(request_rec *r, char **body);
#define MAX_SIZE 1048576
// from Nick Kew's Apache Modules book
int read_post_body(request_rec *r, char **body)
{
int bytes, eos;
apr_size_t count;
apr_status_t rv;
apr_bucket_brigade *bb;
apr_bucket_brigade *bbin;
char *buf;
apr_bucket *b;
apr_bucket *nextb;
const char *clen = apr_table_get(r->headers_in, "Content-Length");
if (clen != NULL){
bytes = strtol(clen, NULL, 0);
if (bytes >= MAX_SIZE) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Request too big (%d bytes; limit %d)",
bytes, MAX_SIZE);
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
}
else {
bytes = MAX_SIZE;
}
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
bbin = apr_brigade_create(r->pool, r->connection->bucket_alloc);
count = 0;
eos = 0;
do {
rv = ap_get_brigade(r->input_filters, bbin, AP_MODE_READBYTES,
APR_BLOCK_READ, bytes);
if (rv != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
}
for (b = APR_BRIGADE_FIRST(bbin);
b != APR_BRIGADE_SENTINEL(bbin);
b = nextb) {
nextb = APR_BUCKET_NEXT(b);
if (APR_BUCKET_IS_EOS(b)) {
eos = 1;
}
if (!APR_BUCKET_IS_METADATA(b)) {
if (b->length != (apr_size_t)(-1)) {
count += b->length;
if (count > MAX_SIZE) {
apr_bucket_delete(b);
}
}
}
if (count <= MAX_SIZE) {
APR_BUCKET_REMOVE(b);
APR_BRIGADE_INSERT_TAIL(bb, b);
}
}
}while (!eos);
if (count > MAX_SIZE) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
"Request too big (%d bytes; limit %d)",
count, MAX_SIZE);
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
buf = apr_palloc(r->pool, count+1);
rv = apr_brigade_flatten(bb, buf, &count);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
"Error (flatten) reading form data");
return HTTP_INTERNAL_SERVER_ERROR;
}
buf[count] = '\0';
//*form = parse_form_from_string(r, buf);
*body = buf;
return OK;
}
/* The sample content handler */
static int nu_handler(request_rec *r)
{
if (strcmp(r->handler, "nu")) {
return DECLINED;
}
r->content_type = "text/html";
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSError *error;
// Get the module configuration
NSString *path = nil;
modnu_config *perdir_cfg = ap_get_module_config(r->per_dir_config, &nu_module);
if (perdir_cfg && perdir_cfg->string) {
path = [[NSString alloc] initWithCString:perdir_cfg->string encoding:NSUTF8StringEncoding];
} else {
modnu_config *s_cfg = ap_get_module_config(r->server->module_config, &nu_module);
if (s_cfg && s_cfg->string) {
path = [[NSString alloc] initWithCString:s_cfg->string encoding:NSUTF8StringEncoding];
}
}
NSString *string = path ? [NSString stringWithContentsOfFile:path] : @"\"Server error: Nu module not configured\"";
NSDictionary *formDict = [NSDictionary dictionary];
if (r->method_number == M_POST) {
printf("we have a post\n");
char *body;
int rv = read_post_body(r, &body);
if (rv == OK) {
printf("%s\n", body);
NSString *postString = [NSString stringWithCString:body encoding:NSUTF8StringEncoding];
formDict = [postString urlQueryDictionary];
}
}
ApacheRequest *request = [[ApacheRequest alloc] init];
[request setRequest:r];
NSString *result;
if (!string) {
result = [error description];
} else {
id parser = [Nu parser];
[parser setValue:request forKey:@"request"];
if (formDict) [parser setValue:formDict forKey:@"form"];
result = [parser parseEval:string];
}
if (!r->header_only) {
ap_rputs([result cStringUsingEncoding:NSUTF8StringEncoding], r);
}
[request release];
[pool release];
return OK;
}
static void nu_register_hooks(apr_pool_t *p)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NuInit();
[pool release];
ap_hook_handler(nu_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
static void *create_modnu_perdir_config(apr_pool_t *p, server_rec *s)
{
modnu_config *newcfg = (modnu_config *) apr_pcalloc(p, sizeof(modnu_config));
newcfg->string = 0;
return (void *) newcfg;
}
static void *create_modnu_config(apr_pool_t *p, server_rec *s)
{
modnu_config *newcfg = (modnu_config *) apr_pcalloc(p, sizeof(modnu_config));
newcfg->string = 0;
return (void *) newcfg;
}
static const char *set_modnu_perdir_string(cmd_parms *parms, void *mconfig, const char *arg)
{
modnu_config *s_cfg = (modnu_config *) mconfig;
s_cfg->string = (char *) arg;
return NULL;
}
static const char *set_modnu_string(cmd_parms *parms, void *mconfig, const char *arg)
{
modnu_config *s_cfg = ap_get_module_config(parms->server->module_config, &nu_module);
s_cfg->string = (char *) arg;
return NULL;
}
static const command_rec mod_nu_cmds[] =
{
AP_INIT_TAKE1(
"NuDefaultHandler",
set_modnu_string,
NULL,
RSRC_CONF,
"NuDefaultHandler (string) Path to the Nu request handler."
),
AP_INIT_TAKE1(
"NuHandler",
set_modnu_perdir_string,
NULL,
ACCESS_CONF,
"NuHandler (string) Path to the Nu request handler."
),
{NULL}
};
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA nu_module = {
STANDARD20_MODULE_STUFF,
create_modnu_perdir_config, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
create_modnu_config, /* create per-server config structures */
NULL, /* merge per-server config structures */
mod_nu_cmds, /* table of config file commands */
nu_register_hooks /* register hooks */
};
// pulled from Nunja/NuHTTP
@interface NSString (ModNu)
/*! URL-encode a string. */
- (NSString *) urlEncode;
/*! Decode a url-encoded string. */
- (NSString *) urlDecode;
/*! Convert a url query into a dictionary. */
- (NSDictionary *) urlQueryDictionary;
@end
@interface NSDictionary (ModNu)
/*! Convert a dictionary into a url query string. */
- (NSString *) urlQueryString;
@end
static unichar char_to_int(unichar c)
{
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A': case 'a': return 10;
case 'B': case 'b': return 11;
case 'C': case 'c': return 12;
case 'D': case 'd': return 13;
case 'E': case 'e': return 14;
case 'F': case 'f': return 15;
}
return 0; // not good
}
static char int_to_char[] = "0123456789ABCDEF";
@implementation NSString(ModNu)
- (NSString *) urlEncode
{
NSMutableString *result = [NSMutableString string];
int i = 0;
int max = [self length];
while (i < max) {
unichar c = [self characterAtIndex:i++];
if (iswalpha(c) || iswdigit(c) || (c == '-') || (c == '.') || (c == '_') || (c == '~'))
#ifdef DARWIN
[result appendFormat:@"%C", c];
#else
[result appendFormat:@"%c", c];
#endif
else
[result appendString:[NSString stringWithFormat:@"%%%c%c", int_to_char[(c/16)%16], int_to_char[c%16]]];
}
return result;
}
- (NSString *) urlDecode
{
NSMutableString *result = [NSMutableString string];
int i = 0;
int max = [self length];
while (i < max) {
unichar c = [self characterAtIndex:i++];
switch (c) {
case '+':
[result appendString:@" "];
break;
case '%':
#ifdef DARWIN
[result appendFormat:@"%C",
#else
[result appendFormat:@"%c",
#endif
char_to_int([self characterAtIndex:i++])*16
+ char_to_int([self characterAtIndex:i++])];
break;
default:
#ifdef DARWIN
[result appendFormat:@"%C", c];
#else
[result appendFormat:@"%c", c];
#endif
}
}
return result;
}
- (NSDictionary *) urlQueryDictionary
{
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *pairs = [self componentsSeparatedByString:@"&"];
int i;
int max = [pairs count];
for (i = 0; i < max; i++) {
NSArray *pair = [[pairs objectAtIndex:i] componentsSeparatedByString:@"="];
if ([pair count] == 2) {
NSString *key = [[pair objectAtIndex:0] urlDecode];
NSString *value = [[pair objectAtIndex:1] urlDecode];
[result setObject:value forKey:key];
}
}
return result;
}
@end
@implementation NSDictionary (ModNu)
- (NSString *) urlQueryString
{
NSMutableString *result = [NSMutableString string];
NSEnumerator *keyEnumerator = [[[self allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator];
id key;
while (key = [keyEnumerator nextObject]) {
if ([result length] > 0) [result appendString:@"&"];
[result appendString:[NSString stringWithFormat:@"%@=%@", [key urlEncode], [[[self objectForKey:key] stringValue] urlEncode]]];
}
return [NSString stringWithString:result];
}
@end
Jump to Line
Something went wrong with that request. Please try again.