DelphiでApacheのモジュールを作成する

Delphi2009でApache2.2(Windows)用のモジュールを作成する方法。Delphi7ぐらいのときは標準でApache2モジュール選べたのになぁ。
使用しているDelphiは2009pro。
Delphi2009になってからも、Apacheのヘッダファイル群をポートしてラップしたクラスが残っています(2009でも問題なく動作する)。

Apache2のインストール

まずはApache2のインストール。使用したApach2のバージョンは2.2.11です。
このあたりからダウンロードしてきましょう。
http://www.apache.jp/misc/download.html
Windows用のインストーラが手に入ったら早速インストール。


設定は適当に。Server Nameはlocalhostでいいと思います。80番ポートが使えない場合は別途調べてインストールどうぞ。

後で必要になるので、Customインストールで "Build Headers and Libraries" もインストールしておきます。

インストールに成功したら、 http://localhost/ にブラウザでアクセスしてApacheが動いているか見てみましょう。

作成するモジュールはApacheのDLLを呼び出すので、Apacheのインストールディレクトリを環境変数のPATHに追加しておきます。

DelphiでWebサーバーアプリケーションを作る

Apacheのインストールができたら、Delphiでアプリケーションを作りましょう。

CGI実行形式で開発を行います。

アクションを一つ作ってHTMLのレスポンスを返すイベントを実装しました。

procedure THelloApp.HelloAppIndexAction(Sender: TObject; Request: TWebRequest;
  Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content :=
      '<html><head>' +
      '<meta http-equiv="content-type" content="text/html; charset=Shift_JIS">' +
      '<title>Apache2モジュール</title></head><body>' +
      '<h1>こんにちはApache</h1>' +
      '</body></html>';
end;

プロジェクトのソースを開いて、Apache用に書き換えます。

library Apache2Hello; // program -> library

{$APPTYPE CONSOLE}

uses
  WebBroker,
  //CGIApp,
  ApacheTwoApp,  // apache 1.xの場合はApacheApp
  uHelloApp in 'uHelloApp.pas' {HelloApp: TWebModule};

{$R *.res}
{$E so}  // 拡張子を.soに

// Apacheから呼ばれるハンドルをエクスポート
exports
  apache_module name 'Apache2Hello_module';

begin
  Application.Initialize;
  Application.CreateForm(THelloApp, HelloApp);
  Application.Run;
end.

さてこれでApache2用のモジュールがビルドされます。Apache2Hello.soファイルができました。

Apacheにモジュールを設定する

Apache2のconfを少し書きます。"C:\Program Files\Apache Software Foundation\Apache2.2\httpd.conf"

LoadModule Apache2Hello_module "C:\sokano\Projects\Delphi\_sample\apache2mod\Apache2Hello.so"
<Location />
  # ファイル名を小文字にしたもの+"-handler"をSetHandlerで指定
  SetHandler apache2hello-handler
</Location>

Apacheを再起動して確認しようとしたところ、モジュールが見つかりませんとエラーがでました。
DelphiApacheモジュールはApacheの "libapr.dll" と "libhttpd.dll" を参照しています。
Apacheのbinディレクトリには、 "libhttpd.dll" はありましたが、"libapr.dll"はなかったので"libapr-1.dll"をこの名前でコピーしておきます。
これで動作するか、と思いきやまたエラーがでました。

httpd: Syntax error on line 484 of F:/Program Files/Apache Software Foundation/Apache2.2/conf/httpd.conf: API module structure 'Apache2Hello_module' in file F:/sokano/Projects/Delphi/_sample/apache2mod/Apache2Hello.so is garbled - expected signature 41503232 but saw 41503230 - perhaps this is not an Apache module DSO, or was compiled for a different Apache version?

Apacheのバージョンが合いませんということのようです。

Apacheのバージョンを合わせる

DelphiのHTTPD2.pasはApache2.0.42用に書かれています。なのでこれを使用するApacheのバージョンに合わせる必要があります。
230行目のこのあたりが原因。2.0.42になっている。

{$HPPEMIT '#include <http_config.h>'}
(*
 * @file http_config.h
 * @brief Apache Configuration
 *)
const
  MODULE_MAGIC_COOKIE = $041503230;                 (* "AP20" *)
  {$EXTERNALSYM MODULE_MAGIC_COOKIE}
  MODULE_MAGIC_NUMBER_MAJOR = 20020903; { Apache 2.0.42 } 
  {$EXTERNALSYM MODULE_MAGIC_NUMBER_MAJOR}
  MODULE_MAGIC_NUMBER_MINOR = 0;                   (* 0...n *)
  {$EXTERNALSYM MODULE_MAGIC_NUMBER_MINOR}
  MODULE_MAGIC_NUMBER = MODULE_MAGIC_NUMBER_MAJOR; (* backward compat *)
  {$EXTERNALSYM MODULE_MAGIC_NUMBER}

MODULE_MAGIC_COOKIEとMODULE_MAGIC_NUMBER_MAJOR、MODULE_MAGIC_NUMBER_MINORを書き換えます。
Apacheのincludeディレクトリからgrepでこの値を探します。
"ap_mmn.h" に同じ値がありました。

#define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */

#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20051115
#endif
#define MODULE_MAGIC_NUMBER_MINOR 21                    /* 0...n */

Delphiのsource\internetディレクトリから "HTTP2.pas" と "ApacheTwoApp.pas" をプロジェクトディレクトリにコピーしてきます。

HTTP2.pasの該当箇所を書き換えます。

{$HPPEMIT '#include <http_config.h>'}
(*
 * @file http_config.h
 * @brief Apache Configuration
 *)
const
  MODULE_MAGIC_COOKIE = $041503232;                 (* "AP20" *)
  {$EXTERNALSYM MODULE_MAGIC_COOKIE}
  MODULE_MAGIC_NUMBER_MAJOR = 20051115; { Apache 2.0.42 }
  {$EXTERNALSYM MODULE_MAGIC_NUMBER_MAJOR}
  MODULE_MAGIC_NUMBER_MINOR = 21;                   (* 0...n *)
  {$EXTERNALSYM MODULE_MAGIC_NUMBER_MINOR}
  MODULE_MAGIC_NUMBER = MODULE_MAGIC_NUMBER_MAJOR; (* backward compat *)
  {$EXTERNALSYM MODULE_MAGIC_NUMBER}

書き換えたら、プログラムの再構築を行います。
Apacheを再起動して、http://localhost/ にアクセスすると「こんにちはApache」と表示されました。

めでたしめでたし。