Wednesday, July 29, 2009

 

Apache 2.2.x modules with FreePascal (Linux)


Finally I have a couple of minutes free to write about Apache 2.2.x Modules in Linux using FreePascal. The methodology is pretty much the same as my previous article about Win32 modules.

The code

Open your favorite editor and type this code, then save it as "mod_helloworld.pp":


{*******************************************
* Test library of the Apache Pascal Headers
********************************************}
library mod_helloworld;

{*******************************************
* The mode must be objfpc on this unit because
* the unix code uses some extensions
* introduced on Free Pascal
********************************************}
{$ifdef fpc}
{$mode objfpc}{$H+}
{$endif}

{$IFDEF WIN32}
{$DEFINE WINDOWS}
{$ENDIF}

{$define Apache2_0}

uses SysUtils, httpd {$ifndef Apache1_3}, apr{$endif};

var
test_module: module; {$ifdef Unix} public name 'test_module'; {$endif}
default_module_ptr: Pmodule;

const
MODULE_NAME = 'mod_helloworld.so';
HANDLER = 'helloworld-handler';

{****************************************************
* Free Pascal only supports exporting
* variables on Windows
*****************************************************}
{$ifdef WINDOWS}
exports
test_module name 'test_module';
{$endif}

{****************************************************
* Handles apache requests
*****************************************************}
function DefaultHandler(r: Prequest_rec): Integer; cdecl;
var
RequestedHandler: string;
begin
RequestedHandler := r^.handler;

{ We decline to handle a request if hello-handler is not the value of r->handler }
if not SameText(RequestedHandler, 'testapache-handler') then
begin
Result := DECLINED;
Exit;
end;

{ The following line just prints a message to the errorlog }
ap_log_error(MODULE_NAME, 54, APLOG_NOERRNO or APLOG_NOTICE,
{$ifndef Apache1_3}0,{$endif} r^.server,
'mod_hello: %s', [PChar('Before content is output')]);

{ We set the content type before doing anything else }
{$ifdef Apache1_3}
r^.content_type := 'text/html';
// ap_send_http_header(r);
{$else}
ap_set_content_type(r, 'text/html');
{$endif}

{ If the request is for a header only, and not a request for
the whole content, then return OK now. We don't have to do
anything else. }
if (r^.header_only <> 0) then
begin
Result := OK;
Exit;
end;

{ Now we just print the contents of the document using the
ap_rputs and ap_rprintf functions. More information about
the use of these can be found in http_protocol.inc }
ap_rputs('<html>' + LineEnding, r);
ap_rputs('<head>' + LineEnding, r);
ap_rputs('<title>Hello There</title>' + LineEnding, r);
ap_rputs('</head>' + LineEnding, r);
ap_rputs('<body bgcolor="#FFFFFF">' + LineEnding ,r);
ap_rputs('<h1>Hello world</h1>' + LineEnding, r);
ap_rputs('This is the first Apache Module working with the new binding from Free Pascal' + LineEnding, r);
// ap_rprintf(r, '<br />A sample line generated by ap_rprintf<br />' + LineEnding, []);
ap_rputs('</body></html>' + LineEnding, r);

{ We can either return OK or DECLINED at this point. If we return
* OK, then no other modules will attempt to process this request }
Result := OK;
end;

{***************************************************
* Registers the hooks
****************************************************}
{$ifdef apache1_3}

procedure hw_init(s: PServer_rec; p: PPool); cdecl;
begin
end;

var
hw_handlers: array[0..0] of handler_rec =
(
(content_type: 'hw_app'; handler: @DefaultHandler)
);

{$else}

procedure RegisterHooks(p: Papr_pool_t); cdecl;
begin
ap_hook_handler(@DefaultHandler, nil, nil, APR_HOOK_MIDDLE);
end;

{$endif}

{***************************************************
* Library initialization code
****************************************************}
begin
default_module_ptr := @test_module;
FillChar(default_module_ptr^, SizeOf(default_module_ptr^), 0);

{$ifdef apache1_3}
STANDARD_MODULE_STUFF(test_module);

with test_module do
begin
name := MODULE_NAME;
init := @hw_init;
handlers := hw_handlers;
end;
{$else}
STANDARD20_MODULE_STUFF(test_module);

with test_module do
begin
name := MODULE_NAME;
register_hooks := @RegisterHooks;
end;
{$endif}
end.


Then stop Apache 2 service.

To compile the module I had to use this on my Debian 5 machine using FPC 2.2.4:


fpc -WR -Xs -XX -Fu/usr/lib/fpc/2.2.4/units/i386-linux/httpd22 mod_helloworld.pp


Pay attention I'm explicitly using the httpd22 path for loading the http.pp related stuff. Without this, the compiler could load the http unit for another version of Apache.

Note: The -WR parameter tells the compiler to add relocatable code to the dll. Without this, you cannot load two dlls compiled with FPC with the same executable.

After compiling the program you will get the file libmod_helloworld, now you have to rename the file to mod_helloworld.so and copy to your Apache/modules directory, usually in /usr/lib/apache2/modules/mod_helloworld.so.

In my Debian 5, Apache2 config files are in /etc/apache2/mods-available. I created the files helloworld.load and helloworld.conf files containing this:

helloworld.load

LoadModule test_module /usr/lib/apache2/modules/mod_helloworld.so


helloworld.conf

<Location /hello>
SetHandler helloworld-handler
</Location>


After this, do an "sudo apache2ctl restart" and go to http://<yourhost>/hello. It should open a page saying "Hello World".

The last article of this series will be the same module for FreeBSD. I'd try to create one, bug got stuck in an issue...at the moment FPC can't create FreeBSD shared libraries, so I'll try to use a workaround to at least, test a basic module.

Friday, July 03, 2009

 

Apache 2.2.x modules with FreePascal (Win32)


Continuing with this series of articles, I will start with the FreePascal version using plain command line FreePascal 2.2.4 for Win32, and later I'll try to create a module for Apache 2.2.x on Linux.

Before copying-pasting this example, I recommend you to read this Wiki to get a detailed knowledge of the problem.

The code

Open your favorite editor and type this code, then save it as "mod_helloworld.pp":


{*******************************************
* Test library of the Apache Pascal Headers
********************************************}
library mod_helloworld;

{*******************************************
* The mode must be objfpc on this unit because
* the unix code uses some extensions
* introduced on Free Pascal
********************************************}
{$ifdef fpc}
{$mode objfpc}{$H+}
{$endif}

{$IFDEF WIN32}
{$DEFINE WINDOWS}
{$ENDIF}

{$define Apache2_0}

uses SysUtils, httpd {$ifndef Apache1_3}, apr{$endif};

var
test_module: module; {$ifdef Unix} public name 'test_module'; {$endif}
default_module_ptr: Pmodule;

const
MODULE_NAME = 'mod_helloworld.so';
HANDLER = 'helloworld-handler';

{****************************************************
* Free Pascal only supports exporting
* variables on Windows
*****************************************************}
{$ifdef WINDOWS}
exports
test_module name 'test_module';
{$endif}

{****************************************************
* Handles apache requests
*****************************************************}
function DefaultHandler(r: Prequest_rec): Integer; cdecl;
var
RequestedHandler: string;
begin
RequestedHandler := r^.handler;

{ We decline to handle a request if hello-handler is not the value of r->handler }
if not SameText(RequestedHandler, 'testapache-handler') then
begin
Result := DECLINED;
Exit;
end;

{ The following line just prints a message to the errorlog }
ap_log_error(MODULE_NAME, 54, APLOG_NOERRNO or APLOG_NOTICE,
{$ifndef Apache1_3}0,{$endif} r^.server,
'mod_hello: %s', [PChar('Before content is output')]);

{ We set the content type before doing anything else }
{$ifdef Apache1_3}
r^.content_type := 'text/html';
// ap_send_http_header(r);
{$else}
ap_set_content_type(r, 'text/html');
{$endif}

{ If the request is for a header only, and not a request for
the whole content, then return OK now. We don't have to do
anything else. }
if (r^.header_only <> 0) then
begin
Result := OK;
Exit;
end;

{ Now we just print the contents of the document using the
ap_rputs and ap_rprintf functions. More information about
the use of these can be found in http_protocol.inc }
ap_rputs('<html>' + LineEnding, r);
ap_rputs('<head>' + LineEnding, r);
ap_rputs('<title>Hello There</title>' + LineEnding, r);
ap_rputs('</head>' + LineEnding, r);
ap_rputs('<body bgcolor="#FFFFFF">' + LineEnding ,r);
ap_rputs('<h1>Hello world</h1>' + LineEnding, r);
ap_rputs('This is the first Apache Module working with the new binding from Free Pascal' + LineEnding, r);
// ap_rprintf(r, '<br />A sample line generated by ap_rprintf<br />' + LineEnding, []);
ap_rputs('</body></html>' + LineEnding, r);

{ We can either return OK or DECLINED at this point. If we return
* OK, then no other modules will attempt to process this request }
Result := OK;
end;

{***************************************************
* Registers the hooks
****************************************************}
{$ifdef apache1_3}

procedure hw_init(s: PServer_rec; p: PPool); cdecl;
begin
end;

var
hw_handlers: array[0..0] of handler_rec =
(
(content_type: 'hw_app'; handler: @DefaultHandler)
);

{$else}

procedure RegisterHooks(p: Papr_pool_t); cdecl;
begin
ap_hook_handler(@DefaultHandler, nil, nil, APR_HOOK_MIDDLE);
end;

{$endif}

{***************************************************
* Library initialization code
****************************************************}
begin
default_module_ptr := @test_module;
FillChar(default_module_ptr^, SizeOf(default_module_ptr^), 0);

{$ifdef apache1_3}
STANDARD_MODULE_STUFF(test_module);

with test_module do
begin
name := MODULE_NAME;
init := @hw_init;
handlers := hw_handlers;
end;
{$else}
STANDARD20_MODULE_STUFF(test_module);

with test_module do
begin
name := MODULE_NAME;
register_hooks := @RegisterHooks;
end;
{$endif}
end.


Then stop Apache 2 service, and compile the file with this command:


fpc -WR -XX -Xs mod_helloworld.pp


Note: The -WR parameter tells the compiler to add relocatable code to the dll. Without this, you cannot load two dlls compiled with FPC with the same executable.

After compiling the program you will get the file mod_helloworld.dll, now you have to rename the file to mod_helloworld.so and copy to your Apache/modules directory, usually in C:\Program files\Apache Software Foundation\Apache2.2\modules.

Now add this to your httpd.conf file in C:\Program files\Apache Software Foundation\Apache2.2\conf:


LoadModule test_module modules/mod_helloworld.so
<Location /hello>
SetHandler helloworld-handler
</Location>


I don't have a Linux box here to test this (shhh, I'm at work), I'll try to compile it this weekend at home in Linux and FreeBSD.

Wednesday, July 01, 2009

 

Apache 2.2.x modules with Delphi II


After my "Apache 2.2.x modules with Delphi" article, I received many requests for an example, and here it is.


Creating the directory structure


Create a directory where your Delphi project will reside, for example C:\myModule, then copy the files HTTPD2.pas, ApacheTwoApp.pas and ApacheTwoHTTP.pas from your Delphi/Source directory to the newly created directory.

Patching HTTPD2.pas

Open the file c:\myModule\HTTPD2.pas and replace/fix the lines as shown in my previous post.

The code

This is a very small HelloWorld WebBroker example, it is composed of only three files, mod_helloworld.dpr, main.pas and main.dfm

mod_helloworld.dpr


library mod_helloworld;

uses
HTTPD2 in 'HTTPD2.pas',
ApacheTwoApp,
WebBroker,
main in 'main.pas' {WebModule1: TWebModule};

{$E so}

{$R *.res}

exports
apache_module name 'helloworld_module';

begin
Application.Initialize;
Application.CreateForm(TWebModule1, WebModule1);
Application.Run;
end.


main.pas


unit main;

interface

uses
SysUtils, Classes, HTTPApp,
HTTPProd;

type
TWebModule1 = class(TWebModule)
procedure WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
public
{ Public declarations }
end;

var
WebModule1: TWebModule1;

implementation

{$R *.dfm}

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
Response.Content := 'Hello from Apache Module!';
end;

end.


main.dfm


object WebModule1: TWebModule1
OldCreateOrder = False
Actions = < default =" True" name =" 'WebActionItem1'" pathinfo =" '/test'" onaction =" WebModule1WebActionItem1Action">
Left = 679
Top = 385
Height = 150
Width = 215
end


Compilling the module

Save the three files in c:\myModule and open the .dpr with Delphi, then compile to your Apache2 modules directory, usually in C:\Program files\Apache Software Foundation\Apache2.2\modules.

Configuring Apache2

If the Apache 2.2 service it's running, please stop it, then open your C:\Program files\Apache Software Foundation\Apache2.2\conf\httpd.conf file and look for the "LoadModule" entries, add this after the last entry:


LoadModule helloworld_module modules/mod_helloworld.so


And below this line add this:


<Location /test>
SetHandler mod_helloworld-handler
</Location>


Testing the module

Restart your Apache 2.2 service and open a web browser, then type http://localhost:8080/test, it should show a page with the text "Hello from Apache Module!".

That's it.

This page is powered by Blogger. Isn't yours?