mod_perl handler skeltons

29 02 2008

Because I rarely write mod_perl handler from scratch, tend to forget very basics of how it should be.Note “bare minimum” mod_perl response handlers here so that I can quickly start writing handlers from copying it.

Suppose installation of Apache 2.2, mod_perl and libapreq2 is successfully finished.

Apache configuration

LoadModule perl_module lib/httpd/mod_perl.so
LoadModule apreq_module lib/httpd/mod_apreq2.so

PerlSwitches -Mlib=/home/www

<Location /hello>
    SetHandler perl-script
    PerlResponseHandler My::Hello
</Location>

<Location /handler>
    SetHandler perl-script
    PerlResponseHandler My::Handler
</Location>

static handler

In /home/www/My/Hello.pm,

package My::Hello;
use strict; use Apache2::RequestRec;
use Apache2::RequestIO;
use Apache2::Const -compile => 'OK';

sub handler : method {
    my ($class, $r) = @_;
    $r->content_type('text/plain');
    print 'Hello, world';
    return Apache2::Const::OK;
}
1;

http://localhost/hello should return ‘Hello, world’.

Dealing with parameters

In /home/www/My/Handler.pm,

package My::Handler;
use strict;

use Apache2::RequestRec;
use Apache2::RequestIO;
use Apache2::Request;
use Apache2::Const -compile => 'OK';

sub handler : method {
    my ($class, $r) = @_;

    $r->content_type('text/plain');

    my $req = Apache2::Request->new($r);
    print $req->param('test1');

    return Apache2::Const::OK;
}

1;

Should take parameter from query like http://localhost/handler?test1=Hello or form like below.

<form action="/handler" method="POST">
<input type="text" name="test1">
<br>
<input type="submit">
</form>




HTTP GET by CFNetwork

24 02 2008

I came across the same problem described in fraserspeirs: HTTP Nerdery, or, Why NSURLConnection Sucks For POST.I tried to send POST reqeust to a HTTP server with NSURLRequest and NSURLConnection, but nothing sent.

So I decided to use CFNetwork instead.Here is my first attempt. Because this code blocks until the server returns HTTP response, I’m modifying to non-blocking version which make use of “Run Loops”.

CFURLRef url = CFURLCreateWithString(NULL, CFSTR("http://www.google.co.jp/"), NULL);
CFHTTPMessageRef httpRequest = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), url, kCFHTTPVersion1_1);
CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(NULL, httpRequest);
CFReadStreamOpen(readStream);

CFIndex bytes;
int bufSize = 1024;
UInt8 buf[bufSize];

do {
    bytes = CFReadStreamRead(readStream, buf, sizeof(buf));
    if( bytes > 0 ){
        NSString *responseString = [[NSString alloc] initWithBytes:buf length:bytes encoding:NSUTF8StringEncoding];
        NSLog(responseString);
    } else if( bytes < 0 ) {
        CFStreamError error = CFReadStreamGetError(readStream);
    }
} while( bytes > 0 );

CFHTTPMessageRef httpResponse = (CFHTTPMessageRef)CFReadStreamCopyProperty(readStream, kCFStreamPropertyHTTPResponseHeader);

if(httpResponse) {
    CFStringRef responseStatus = CFHTTPMessageCopyResponseStatusLine(httpResponse);
    NSLog((NSString *)responseStatus);
}




URL encoding

23 02 2008

I look for Cocoa methods those can perform “URL encode”, just like uri_escape in perl. NSString’s stringByAddingPercentEscapesUsingEncoding: works for some characters, but does not encode characters like ‘=’(equal) and ‘ ‘(white space).

However, CoreFoundation function CFURLCreateStringByAddingPercentEscapes does what I want.

CFStringRef param1_encoded = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)param1, NULL, (CFStringRef)@";/?:@&=+$,", kCFStringEncodingUTF8);

It seems that this fact is rediscovered by many Cocoa developers…





Calculating MD5

19 02 2008

On Leopard, you can use CC_MD5 function to produce MD5 hashed data. Here is a code snippet which computes MD5 from NSString.

#import <CommonCrypto/CommonDigest.h>             // contains declaration of CC_MD5 

NSString *testString = @"Test";                   // String data that needs md5 checksum
const char *test_cstr = [testString UTF8String];  // Get data as C language string.
unsigned char md5_result[CC_MD5_DIGEST_LENGTH];   // storage for checksum result
CC_MD5(test_cstr, strlen(test_cstr), md5_result); // do calculation

If you want hexadecimal representation of the checksum as NSString, use stringWithFormat(taken from CocoaDev: MDFive).

NSString *hex_str = [NSString stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
md5_result[0], md5_result[1],
md5_result[2], md5_result[3],
md5_result[4], md5_result[5],
md5_result[6], md5_result[7],
md5_result[8], md5_result[9],
md5_result[10], md5_result[11],
md5_result[12], md5_result[13],
md5_result[14], md5_result[15]];

NSLog(hex_str);

In case you are not sure if the result is correct or not, compare hexidecimal string with other calculation method.
Try this.

perl -MDigest::MD5=md5_hex -le 'print md5_hex("Test")'




Base64 encoding in Cocoa

16 02 2008

While there are implementations written in Objective-C or making use of openssl(CocoaDev: BaseSixtyFour), on Leopard, you can also use Apache Portable Runtime functions.

1. Import header files nessesary to base64 encoding.

#import <apr-1/apr.h>
#import <apr-1/apr_base64.h>

2. Add linker flags.
Open “build settings” dialog page, add following flags to OTHER_LDFLAGS item(screenshot is taken in Japanese environment).

-laprutil-1 -lapr-1

linker_flag1

3. apr functions cannot recognize NSString nor CFStringRef, make wrapper around.

static NSString* encode_to_base64(NSString* source_str)
{
    char *source_cstr = (char*)[source_str UTF8String];

    int source_length = strlen(source_cstr);
    int result_length = apr_base64_encode_len(source_length);
    char *encoded_buf = malloc(result_length);
    apr_base64_encode(encoded_buf, source_cstr, source_length);

    NSString *resultString = [NSString stringWithCString:encoded_buf];

    free(encoded_buf);
    return resultString;
}

4. Use above routine in your program.

NSString *testString = @"Test";
NSString *base64String = encode_to_base64(testString);