Recent

Author Topic: Solved: Cant get FPC fpweb Apache 2.4 module to work. Ubuntu 24.04, Lazarus 4.0  (Read 4204 times)

vangli

  • Jr. Member
  • **
  • Posts: 56
Hi. I am running:
Ubuntu 24.04 (64 bit)
Apache 2.4.54
Lazarus 4.0
FPC 3.2.2

Following the tutorial: https://wiki.lazarus.freepascal.org/fpWeb_Tutorial

I started with creating new apache module application from Lazarus list of new projects, just renaming some paramters.

I am not able to get this simple module (atached and showed below) to work on an Apache 2.4 server installation. It seems to install correctly, and are listed as shared installed module according to apachectl -M. When module is disabled in apache configuration, a test file is viewed in a connected browser. When activated I got a time out with the following error in the apache error log:

An unhandled exception occurred at $00007690F2105239:
EHTTP: No REQUEST_METHOD passed from server.
  $00007690F2105239
  $00007690F20DEF8C


This message, as far as I can see and traced, is created by some exception in the unit custapache24. So I am rather certain that the module is called from Apache. But, what to do?

When compiling I got the the following messages from Lazarus:

Compile Project, Mode: Release, Target: /home/username/Pascal/MyApacheModul/lib/x86_64-linux/libmod_bvweb.so: Success, Hints: 2
mainunit.pas(15,50) Hint: Parameter "ARequest" not used
mod_bvweb.lpr(66,44) Hint: Variable "DefaultModule" does not seem to be initialized


I think this is OK, however a little curious about the "DefaultModule" not initialized.

My search has revealed that the same EHTTP error occured in reports several years ago, in earlier versions of Lazarus. I wonder what I am missing. Is it some initializing I have to do? Do I use the the turorial in a wrong way? Am I missing some "special" setting in apache configuration? Or am I a big bug myself?  ;D Does anyone know what to do?

I am doing this as a learning session, and have earlier succesfully created small CGI for apace, or http server applications using FPC.

Code: Pascal  [Select][+][-]
  1. Library mod_bvweb;
  2.  
  3. { Add Apache configuration to load module
  4.   ----------------------------------------
  5.   Create bvweb.conf file in /etc/apache2/mods-available directory with content
  6.   as follows,
  7.  
  8.   <IfModule bvweb_module>
  9.     # handle all files having .bv extension
  10.     AddHandler bvweb_handler .bv
  11.   </IfModule>
  12.  
  13.   Create bvweb.load file in /etc/apache2/mods-available directory with content
  14.   as follows,
  15.  
  16.   LoadModule bvweb_module /path/to/libmod_bvweb.so
  17.  
  18.   Do not forget to replace /path/to/libmod_bvweb.so with actual path of
  19.   libmod_bvweb.so. It is important that you use bvweb_module to identify
  20.   module and bvweb_handler to identify handler.
  21.  
  22.   Enable bvweb_module
  23.   ----------------------------------------
  24.   Create symlink to bvweb.conf and bvweb.load in /etc/apache2/mods-enabled directory
  25.  
  26.   $ cd /etc/apache2/mods-enabled
  27.   $ sudo ln -s /etc/apache2/mods-available/bvweb.conf
  28.   $ sudo ln -s /etc/apache2/mods-available/bvweb.load
  29.  
  30.   Restart Apache
  31.   ---------------------------------------
  32.   $ sudo systemctl restart apache2
  33. }
  34.  
  35. {$mode objfpc}{$H+}
  36.  
  37. Uses
  38. {$ifdef unix}
  39.   cthreads,
  40. {$endif}
  41.   httpd24, custapache24, fpapache24, sysutils, mainunit;
  42.  
  43. Const
  44.  
  45. { The following constant is used to export the module record. It must
  46.   always match the name in the LoadModule statement in the apache
  47.   configuration file(s). It is case sensitive !}
  48.   ModuleName='bvweb_module';
  49.  
  50. { The following constant is used to determine whether the module will
  51.   handle a request. It should match the name in the SetHandler statement
  52.   in the apache configuration file(s). It is not case sensitive. }
  53.  
  54.   HandlerName='bvweb_handler';
  55.  
  56. Var
  57.   DefaultModule : module; {$ifdef unix} public name ModuleName;{$endif unix}
  58.  
  59. Exports Defaultmodule name ModuleName;
  60.  
  61. begin
  62.   Application.Title         := 'bvweb_module';
  63.   Application.ModuleName    := ModuleName;
  64.   Application.HandlerName   := HandlerName;
  65.   Application.SetModuleRecord(DefaultModule);
  66.   Application.Initialize;
  67. end.
  68.  

Code: Pascal  [Select][+][-]
  1. unit mainunit;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils, Classes, httpdefs, fpHTTP, fpWeb;
  9.  
  10. type
  11.  
  12.   { TBvFPWebModule }
  13.  
  14.   TBvFPWebModule = class(TFPWebModule)
  15.     procedure DataModuleRequest(Sender: TObject; ARequest: TRequest;
  16.       AResponse: TResponse; var Handled: Boolean);
  17.   private
  18.  
  19.   public
  20.  
  21.   end;
  22.  
  23. var
  24.   BvFPWebModule: TBvFPWebModule;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TBvFPWebModule }
  31.  
  32. procedure TBvFPWebModule.DataModuleRequest(Sender: TObject;
  33.   ARequest: TRequest; AResponse: TResponse; var Handled: Boolean);
  34. begin
  35.   AResponse.Content := '<p>This module works!</p>';
  36.   Handled           := True;
  37. end;
  38.  
  39. initialization
  40.   RegisterHTTPModule('BvFPWebModule', TBvFPWebModule);
  41. end.

Bent, Oslo, Norway
« Last Edit: August 23, 2025, 03:26:51 pm by vangli »
Regards Bent

vangli

  • Jr. Member
  • **
  • Posts: 56
Hi
I have not been able to find a solution yet, mostly caused by lack of knowledge. However, some observations had been done.
  • The module seems to be correctly loaded and initialized seen from the Apache server side.
  • Viewing Apaches error log show several attempts to call the module before timing out. No request method passed from server.
  • Trying to do some older tricks found on different forums, doesn't work. The Apache server will then not load the module.
  • Using Apache 2.2 and the units for this version, seems to work correctly according to reports on some forums.
Could it be one or more of?
  • The module is correctly loaded and initialized by Apache. However the request information, a rather huge record, is wrongly interpreted by the fpc lazweb units, thus giving empty request method.
  • The module is correctly loaded and initialized by Apache. A hook internally in a lazweb unit isn't set or set incorrectly.
  • The module is correctly loaded and initialized by Apache. Some extra user handling/hook/setup is needed for correct interaction with the lazweb units.
  • The module is correctly loaded and initialized by Apache. Some undocumented setup in Apache configuration file is needed.
  • The module is wrongly reported as correctly loaded and initialized by Apache.
Personally I don't think 5. is plausible. Any opinions?
Regards Bent

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Use fpc main branch, you simply need to replace fpapache with fpapache24. The module interface between the two Apache versions have changed.

vangli

  • Jr. Member
  • **
  • Posts: 56
Hi Leledumbo

Thanks very much for answering. However, I already use fpapache24 as you can see in the example above. I know the original solution was working for Apache 2.2 modules. I also know, not in detail, that the module interface has changed from Apache version 2.2 to 2.4. I am now in process of using an alternative route using the unit apr24 directly. I found a description on Internet which I now try to fit. If I got this to work, I may be able to to trace down the original problem. The Apache module need a hook into the handler name with some type of active response. In version 2.2 you had some default behavior which is not longer implemented for version 2.4, if I correctly understand the API description on Apache.org.

I like to have such problems, either it is me myself or in fact a real technical reason. 8)

Best regards Bent
Regards Bent

vangli

  • Jr. Member
  • **
  • Posts: 56
I found this on gitlab: https://gitlab.com/freepascal.org/fpc/source/-/blob/main/packages/httpd24/examples/mod_hello.pp?ref_type=heads

When copying the above example and do some modifications, I got this working Linux (Ubuntu 24.04) example:
Code: Pascal  [Select][+][-]
  1. library mod_bvweb2;
  2. {< Apache 2.4 module.
  3.  
  4.    Based uppon https://gitlab.com/freepascal.org/fpc/source/-/blob/main/packages/httpd24/examples/mod_hello.pp?ref_type=heads
  5.  
  6. }
  7.  
  8. {$mode ObjFPC}{$H+}
  9.  
  10. uses
  11.   Classes, SysUtils, httpd24, apr24;
  12.  
  13. const
  14.   AP24_MODULE_NAME  = 'bvweb-module2';
  15.   AP24_HANDLER_NAME = 'bvweb-handler2';
  16.  
  17. var
  18.   My_Module : module; {$ifdef unix} public name AP24_MODULE_NAME;{$endif}
  19.  
  20. exports
  21.   My_Module name AP24_MODULE_NAME;
  22.  
  23. function MyHandler(r : Prequest_rec): Integer; cdecl;
  24. var
  25.   RequestedHandler, onerow: ansistring;
  26. begin
  27.   RequestedHandler := r^.handler;
  28.   if not SameText(RequestedHandler, AP24_HANDLER_NAME) then { May have several handlers. }
  29.   begin
  30.     Result := DECLINED;
  31.     Exit; // Do not handle
  32.   end;
  33.  
  34.   { The following line just prints a message to the errorlog }
  35.   ap_log_error(AP24_MODULE_NAME,                    // The file in which this function is called
  36.                40,                                  // The line number on which this function is called
  37.                0,                                   // The module_index of the module generating this message
  38.                APLOG_NOERRNO or APLOG_NOTICE,       // The level of this error message
  39.                0,                                   // The status code from the previous command
  40.                r^.server,                           // The server on which we are logging
  41.                AP24_MODULE_NAME+': %s',             // The format string
  42.                [PAnsiChar('Handler: '+AP24_HANDLER_NAME+'. Before content is output!')]); //The arguments to use to fill out fmt.
  43.  
  44.   ap_set_content_type(r, 'text/html');
  45.  
  46.   { If the request is for a header only, and not a request for the whole content, then return
  47.     OK now. We don't have to do anything else. }
  48.   if (r^.header_only <> 0) then
  49.   begin
  50.     Result := OK;
  51.     Exit;
  52.   end;
  53.  
  54.   { Now we just print the contents of the document using the  ap_rputs and ap_rprintf functions. More
  55.     information about the use of these can be found in http_protocol.inc }
  56.   onerow := '<HTML>' + LineEnding;
  57.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  58.   onerow := '<HEAD>' + LineEnding;
  59.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  60.   onerow := '<TITLE>This works</TITLE>' + LineEnding;
  61.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  62.   onerow := '</HEAD>' + LineEnding;
  63.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  64.   onerow := '<BODY BGCOLOR="#FFFFFF">' + LineEnding;
  65.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  66.   onerow := '<H1>Hi, I am here</H1>' + LineEnding;
  67.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  68.   onerow := 'This is an Apache Module working with the binding from Free Pascal' + LineEnding;
  69.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  70.   onerow := '</BODY></HTML>' + LineEnding;
  71.   ap_rwrite(PAnsiChar(onerow), length(onerow), r);
  72.  
  73.   { We can either return OK or DECLINED at this point. If we return OK, then no other modules
  74.     will attempt to process this request }
  75.   Result := OK;
  76.  
  77. end;
  78.  
  79. {*******************************************************************
  80. *  Registers the hooks
  81. *******************************************************************}
  82. procedure RegisterHooks(p: Papr_pool_t); cdecl;
  83. begin
  84.   ap_hook_handler(@MyHandler, nil, nil, APR_HOOK_MIDDLE);
  85. end;
  86.  
  87. {*******************************************************************
  88. *  Library initialization code
  89. *******************************************************************}
  90.  
  91. begin
  92.   Initialize(My_Module);
  93.   FillChar(My_Module, SizeOf(My_Module),0); // Probably double up initializing. Has to test this.
  94.  
  95.   STANDARD20_MODULE_STUFF(My_Module);
  96.  
  97.   with My_Module do
  98.   begin
  99.     name := AP24_MODULE_NAME;
  100.     register_hooks := @RegisterHooks;
  101.   end;
  102. end.
  103.  

You may use this example by creating a new library project in Lazarus IDE. Copy the example overwriting the few lines created by the Lazarus template for libraries. The entering Project options, Compiler options, Compilation and linking. There you enable Smart linkable (-CX), Relocatable (-WR) and Link smart (-XX). Then build the project. This will create a "lib_bvweb2.so" file (on Windows a dll file which is not tested).

Creating corresponding configuration files for the apache server in /etc/apache2/mods-available/:
  • File bvweb2.load containing:
    LoadModule bvweb-module2 /path-to-file/libmod_bvweb2.so
  • File bvweb2.conf containing:
    <IfModule bvweb-module2>
        # handle all files having .bv2 extension
        AddHandler bvweb-handler2 .bv2
    </IfModule>

Then, cd to /etc/apache2/mods-enabled/, and the do:

ln -s /etc/apache2/mods-available/bvweb2.load
ln -s /etc/apache2/mods-available/bvweb2.load


Then just restart the apache web server by:

systemctl restart apache2

Then call your server with a link ending with .bv2.

STATUS
I now has a working module using a more direct approach, not using the Lazarus IDE Apache creation template. This more direct approach shows how to register and hook the handler to the module process. May this be missing in the Lazarus ID Apache module project template or the supporting units? This is the next quest I would dig into. Having something that works may do problem-finding/debugging a little bit more easy  ::)

Bent


Regards Bent

vangli

  • Jr. Member
  • **
  • Posts: 56
Well, I haven't found a real solution to the original problem. However, this is a workaround using the underlying API
directly. This means you use the units httpd24 and apr24 with their include files. As mentioned in my first post in
this thread, it was mainly for learning purposes I started this. It was a steep learning curve and many mistakes, before
I got it to work properly. The coding is more like "brutal" than elegant and optimized. I do not pretend to be a professional
programmer, more likly a hobbyist. Despite this it show some examples that may help you to start with.

The library code showed below is in one file only, with comments. Please feel free to use and skip those things you
don't need.

Code: Pascal  [Select][+][-]
  1. library mod_bvweb2;
  2. {< Apache 2.4 module.
  3.  
  4.    Based uppon https://gitlab.com/freepascal.org/fpc/source/-/blob/main/packages/httpd24/examples/mod_hello.pp?ref_type=heads
  5.  
  6.    In this code I try to shows how to use three different handlers in a single Apache 2.4 module. The last example also
  7.    shows one way to collect paramters from the client. I have modified the code so to emphasize the use of UT8 character
  8.    encoding. I think it also will work on Apache running on Windows, but this is not tested in any way.
  9.  
  10.    Disclaimer: I am not a professional programmer, so please take my statements with a grain of salt, maybe many grains. I
  11.    have done this for learning and exersice my pensionaire brain somewhat. The example use "brute force coding", meaning,
  12.    when it works, go further on, instead of beautification and optimizing.
  13.  
  14.    Code is developed for and tested on:
  15.    - Ubuntu 24.04 (64 bit)
  16.    - Apache 2.4.58
  17.    - Using Lazarus 4.0. and and later on 4.2, both with Freepascal 3.2.2. Both Lazarus version will work just fine.
  18.    - For Lazarus, you may need to install LazWeb, found in OPM.
  19.  
  20.    For the module to work, you need some configuration settings on the Apache server side. In this example on Ubuntu 24.04, you
  21.    first create the file "bvweb2.load" in the directory "/etc/apache2/mods-available" containing:
  22.  
  23.    LoadModule bvweb-module2 /path-to/libmod_bvweb2.so
  24.  
  25.    Then the file "bvweb2.conf", in the same directory, containing:
  26.  
  27.    <IfModule bvweb-module2>
  28.      # handle files having .bv2 and .bv3  extensions
  29.      AddHandler bvweb-handler2 .bv2
  30.      AddHandler bvweb-handler3 .bv3
  31.      <Location "/func">
  32.        # handle everything from this directory
  33.        SetHandler bvweb-handler-func
  34.      </Location>
  35.    </IfModule>
  36.  
  37.    Then you move to the directory "/etc/apache2/mods-enabled" and do the following to linking commands:
  38.  
  39.    ln -s /etc/apache2/mods-available/bvweb2.load
  40.    ln -s /etc/apache2/mods-available/bvweb2.conf
  41.  
  42.    And as the last thing, restart the apache server:
  43.  
  44.    systemctl restart apache2
  45.  
  46.    You may need root access for doing this. On other plattforms similar actions has to be done in an
  47.    apropriate way.
  48.  
  49.    Test the result in a web reader calling it with something like http://server/test.bv2 or
  50.    http://server/test.bv2. You don't need a physical file for this. The handler will catch the call.
  51.  
  52.    Nice readings:
  53.  
  54.         https://httpd.apache.org/docs/2.4/developer/
  55.         https://httpd.apache.org/docs/2.4/developer/modguide.html
  56.  
  57.    I strongly advice you to read the last one thoroughly.
  58.  
  59. }
  60.  
  61. {$mode ObjFPC}{$H+}
  62.  
  63. uses
  64.   Classes, SysUtils, httpd24, apr24;
  65.  
  66. const
  67.   AP24_MODULE_NAME       = 'bvweb-module2';   // The module name
  68.   AP24_HANDLER_NAME      = 'bvweb-handler2';  // You may have several handlers in one module. Remember those names has to be unique across all handlers seen from the Apache server
  69.   AP24_HANDLER_NAME2     = 'bvweb-handler3';
  70.   AP24_HANDLER_NAME_FUNC = 'bvweb-handler-func';
  71.  
  72. type
  73.   TKeyValuePair = record
  74.     key   : PChar;
  75.     value : PChar;
  76.   end;
  77.   TKeyValueArray = array of TKeyValuePair;
  78.   PFormPair      = ^ap_form_pair_t;
  79.  
  80. var
  81.   My_Module : module; {$ifdef unix} public name AP24_MODULE_NAME;{$endif}
  82.  
  83. exports
  84.   My_Module name AP24_MODULE_NAME;
  85.  
  86. //*********** Read POST ********************************************************//
  87. { This is a converted and rewritten C-code example from Apache 2.4. module API.
  88.   It is used to fetch the POST parameters.}
  89. function readPost(var pairs : Papr_array_header_t): TKeyValueArray;
  90. var
  91.   Mylen     : apr_off_t = 0;    // Signed 64 bit integer.
  92.   Size      : apr_size_t;       // Unsigned 64 bit integer.
  93.   I         : Integer = 0;      // Local counter.
  94.   buffer    : PChar;            // Buffer to held a single value.
  95.   pair      : PFormPair;        // To held a POST key/value pair.
  96.   MyRes     : apr_status_t;     // May not need this status variable. Length value??
  97. begin
  98.   Result := nil;
  99.   I := 0;
  100.   while (pairs <> nil) and (apr_is_empty_array(pairs) = 0) do
  101.   begin
  102.     pair  := PFormPair(apr_array_pop(pairs));             // Note that I think this is a destructive fetching process.
  103.     MyRes := apr_brigade_length(pair^.value, 1, @MyLen);  // Finfd the length og POST value.
  104.     if MyRes <> 0 then Break;                             // Ich, an error. Hopefully never seen.
  105.     Size  := apr_size_t(MyLen);                           // Just type convert length.
  106.     Getmem(buffer, size + 1);                             // Prepare for chr(0) ending.
  107.     apr_brigade_flatten(pair^.value, buffer, @size);      // Length of POST variable.
  108.     buffer[Mylen] := #0;                                  // Add PChar line ending, aka Char(0).
  109.     SetLength(Result,I + 1);                              // Adjust length of standard FPC dynamic array.
  110.     Result[I].key   := pair^.name;                        // Copy key name foor value.
  111.     Result[I].value := buffer;                            // Copy value to array.
  112.     Inc(I);
  113.     if I >= 1000 then Break;                              // Just a safety plug for eventually run-away due to sloppy developer work. ;-)
  114.   end;
  115. end;
  116.  
  117. //*********** Example 1 *********************************************************//
  118. { This is an example of userfunction you define yourself. I may be wise to create
  119.   an own unit collecting all procedures, functions and handling you want to use. }
  120. procedure UserProcedure_1(var S : string; r : Prequest_rec);
  121. var
  122.   MyFileName : string;
  123. begin
  124.   MyFileName := r^.filename;
  125.   S := '<html>' + LineEnding
  126.      + '<head>' + LineEnding
  127.      + '<title>UserProcedure_1</title>' + LineEnding
  128.      + '</head>' + LineEnding
  129.      + '<body bgcolor="#ffffff">' + LineEnding
  130.      + '<h1>Output from UserProcedure_1</h1>' + LineEnding
  131.      + '<p>This is an Apache Module working with the binding from Free Pascal. Filename: ' + MyFileName + '.</p>' + LineEnding
  132.      + '<p>Testing some norwegian special characters (2 byte sizes): ÆØÅ and æøå.</p>' + LineEnding
  133.      + '</body></html>' + LineEnding     ;
  134. end;
  135.  
  136. //*********** Example 2 *********************************************************//
  137. { This is the second example of userfunction you define yourself. I may be wise to
  138.   instead create an own unit collecting all proceduresm functions and handling
  139.   you want to use. }
  140. procedure UserProcedure_2 (var S : string; r : Prequest_rec);
  141. var
  142.   SL         : TStringList;
  143.   MyFileName : string;
  144. begin
  145.   MyFileName := r^.filename;
  146.   SL         := TStringList.Create;
  147.   try
  148.     with SL do
  149.     begin
  150.       Append('<html>');
  151.       Append('<head>');
  152.       Append('<title>UserProcedure_2</title>');
  153.       Append('</head>');
  154.       Append('<body bgcolor="#ffffff">');
  155.       Append('<h1>Output from UserProcedure_2</h1>');
  156.       Append('<p>This is an Apache Module working with the binding from Free Pascal. Filename: ' + MyFileName + '.</p>');
  157.       Append('<p>Testing some norwegian special characters (2 byte sizes): ÆØÅ and æøå.</p>');
  158.       Append('</body></html>');
  159.     end;
  160.     S := SL.Text;
  161.   finally
  162.     SL.Free;
  163.   end;
  164. end;
  165.  
  166. //*********** Example 3 *********************************************************//
  167. { This is the third example of userfunction you define yourself. It show using a
  168.   directory has the triggering point. It also incorporates using parameters sent from
  169.   the client. It may be wise to create an own unit collecting  all procedures,
  170.   functions and handling you want to use. }
  171. procedure UserProcedure_Func(var S : string; r : Prequest_rec);
  172. var
  173.   MyFileName  : string;
  174.   MyArguments : string;
  175.   MyGetParam  : string;
  176.   MyMethod    : string;
  177.   MyHeaders   : papr_table_t;
  178.   MyGetTable  : papr_table_t;
  179.   MyPostTable : papr_array_header_t;
  180.   Fields      : papr_array_header_t;
  181.   E           : papr_table_entry_t;
  182.   N           : Integer;             // Helper variable.
  183.   P           : Pointer;             // Helper variable. Used to help me understanding the castings done. And also used for loop count.
  184.   Res         : Integer;             // Variable to keep status from parsing.
  185.   KvpArray    : TKeyValueArray;
  186. begin
  187.   MyFileName  := r^.filename;               // Not working for <Location>. Gives only location like "/func".
  188.   MyFileName  := r^.uri;                    // Gives both location and filename like "/func/test.bv2".
  189.   MyArguments := r^.args;                   // Gives GET parameter(s) as one one PChar string (All after the ? mark).
  190.   MyMethod    := r^.method;                 // Gives POST or GET in my examples. POST if POST and GET are both used.
  191.   MyHeaders   := r^.headers_in;             // Table with all headers.
  192.   Fields      := apr_table_elts(MyHeaders);
  193.   P           := Fields^.elts;
  194.   E           := P;
  195.   N           := Fields^.nelts;
  196.   ap_args_to_table(r,@MyGetTable);
  197.   Res := ap_parse_form_data(r, nil, @MyPostTable, High(apr_size_t), HUGE_STRING_LEN); // Apache API state using -1 as 4th parameter, meaning unlimited, even it is an unsigned integer type. Tells max size
  198.   MyGetParam := apr_table_get(MyGetTable, 'testparam');
  199.   S := '<html>' + LineEnding
  200.      + '<head>' + LineEnding
  201.      + '<title>UserProcedure_Func</title>' + LineEnding
  202.      + '</head>' + LineEnding
  203.      + '<body bgcolor="#ffffff">' + LineEnding
  204.      + '<h1>Output from UserProcedure_3</h1>' + LineEnding
  205.      + '<p>This is an Apache Module working with the binding from Free Pascal. URI: ' + MyFileName + '.</p>' + LineEnding
  206.      + '<p>Testing some norwegian special characters (2 byte sizes): ÆØÅ and æøå.</p>' + LineEnding
  207.      + '<p>Testing POST 1: <form action="http://vax02.local/func/test.bv2?testparam1=charlie" method="post">' + LineEnding
  208.      + '  <label for="data1">Data 1:</label>' + LineEnding
  209.      + '  <input type="text" id="data1" name="data1">' + LineEnding
  210.      + '  <label for="data2">Data 2:</label>' + LineEnding
  211.      + '  <input type="text" id="data2" name="data2">' + LineEnding
  212.      + '  <input type="submit" value="Submit">' + LineEnding
  213.      + '</form></p>' + LineEnding
  214.      + '<p>This is a function called from location configuration for testing parameters.</p>' + LineEnding
  215.      + '<p>GET parameter: testparam=' + MyGetParam + '.</p>' + LineEnding
  216.      + '<p>Arguments: ' + MyArguments + '.</p>' + LineEnding
  217.      + '<p>Method: ' + MyMethod + '.</p>' + LineEnding
  218.      + '<p>Header count: ' + IntToStr(N) + '.</p>' + LineEnding;
  219.   for N := 0 to N - 1 do
  220.   begin
  221.     S := S + 'Header ' + IntToStr(N) + ': ' + E[N].key + ' = ' + E[N].val + '<br>' + LineEnding; // List all headings with key and values.
  222.   end;
  223.   if (Res = OK) and  (MyPostTable^.nelts > 0) then
  224.   begin
  225.     S := S + '<p>Found ' + IntToStr(MyPostTable^.nelts) + ' POST parameter(s)!</p>' + LineEnding;
  226.     S := S + '<p>Length of POST section: ' + IntToStr(MemSize(MyPostTable)) + '.</p>' + LineEnding; // Wonder if this is correct! Seems a bit strange.
  227.     S := S + '<p>Found the following POST parameter(s):</p>' + LineEnding;
  228.     if (Res = OK) or (MyPostTable <> nil) then
  229.     begin
  230.       KvpArray := readPost(MyPostTable);
  231.       for N := 0 to Length(KvpArray) - 1 do
  232.       begin
  233.         S := S + '<p>Key ' + IntToStr(N) + ': ' + KvpArray[N].key + ', Value ' + IntToStr(N) + ': ' + KvpArray[N].value + '.</p>' + LineEnding;
  234.       end;
  235.     end;
  236.   end;
  237.   S := S + '</body></html>' + LineEnding;
  238. end;
  239.  
  240.  
  241. { This is the function that handles requests from the Pache server. The apache server will
  242.   call every module in turn until one module handles the request represented by the handler name. }
  243. function MyHandler(r : Prequest_rec): Integer; cdecl;
  244. var
  245.   RequestedHandler : string;
  246.   S                : string  = '';
  247. begin
  248.   RequestedHandler := r^.handler;
  249.   if not (SameText(RequestedHandler, AP24_HANDLER_NAME)  or
  250.           SameText(RequestedHandler, AP24_HANDLER_NAME2) or
  251.           SameText(RequestedHandler, AP24_HANDLER_NAME_FUNC)
  252.          ) then // May have several handlers. Then several tests. If no match, exit imidiate.
  253.   begin
  254.     Result := DECLINED;
  255.     Exit;       // Do not handle and return to the Apache server.
  256.   end;
  257.  
  258.   { The following line just prints a message to the errorlog }
  259.   ap_log_error(AP24_MODULE_NAME,                    // The file in which this function is called
  260.                40,                                  // The line number on which this function is called
  261.                0,                                   // The module_index of the module generating this message
  262.                APLOG_NOERRNO or APLOG_NOTICE,       // The level of this error message
  263.                0,                                   // The status code from the previous command
  264.                r^.server,                           // The server on which we are logging
  265.                AP24_MODULE_NAME+': %s',             // The format string
  266.                [PAnsiChar('Handler: '+RequestedHandler+'. Before content is output!')]); //The arguments to use to fill out fmt.
  267.  
  268.   ap_set_content_type(r, 'text/html;charset=utf8'); // Set page character encoding to UTF8.
  269.  
  270.   { If the request is for a header only, and not a request for the whole content, then return
  271.     OK now. We don't have to do anything else. According to the Apache documentation, setting
  272.     Result := DONE the server will not further continue to process the request. The result OK
  273.     may let the server to do more processing in other handlers, typically the logging handle.}
  274.   if (r^.header_only <> 0) then
  275.   begin
  276.     Result := OK;
  277.     Exit;
  278.   end;
  279.  
  280.   { Now we just print the contents of the document using the ap_rwrite. More
  281.     information about the use of these can be found in http_protocol.inc. Sometimes
  282.     you will prefere using ap_rputs() function, like ap_rputs('A text string',r).
  283.     A simple case statement is useful for selecting correct process based upon the
  284.     handler name.}
  285.   case RequestedHandler of
  286.     AP24_HANDLER_NAME      : UserProcedure_1(S,r);
  287.     AP24_HANDLER_NAME2     : UserProcedure_2(S,r);
  288.     AP24_HANDLER_NAME_FUNC : UserProcedure_Func(S,r);
  289.   end;
  290.   ap_rwrite(PUTF8String(S),Length(S), r);
  291.  
  292.   { We can either return OK, DONE or DECLINED at this point. If we return DONE, then
  293.     no other modules will attempt to process this request }
  294.   Result := OK;
  295. end;
  296.  
  297. {*******************************************************************
  298. *  Registers the hooks
  299. *******************************************************************}
  300. procedure RegisterHooks(p: Papr_pool_t); cdecl;
  301. begin
  302.   ap_hook_handler(@MyHandler, nil, nil, APR_HOOK_MIDDLE);
  303. end;
  304.  
  305. {*******************************************************************
  306. *  Library initialization code
  307. *******************************************************************}
  308. begin
  309.   Initialize(My_Module);
  310.   FillChar(My_Module, SizeOf(My_Module),0); // Will test if only Initialize() is enough
  311.  
  312.   STANDARD20_MODULE_STUFF(My_Module);       // Yes, same structure as Apache 2.4.
  313.  
  314.   with My_Module do
  315.   begin
  316.     name := AP24_MODULE_NAME;
  317.     register_hooks := @RegisterHooks;
  318.   end;
  319. end.
  320.  

On my server I got this html output from the webserver using example three in above code.

<html>
<head>
<title>UserProcedure_Func</title>
</head>
<body bgcolor="#ffffff">
<h1>Output from UserProcedure_3</h1>
<p>This is an Apache Module working with the binding from Free Pascal. URI: /func/test.bv2.</p>
<p>Testing some norwegian special characters (2 byte sizes): ÆØÅ and æøå.</p>
<p>Testing POST 1: <form action="http://ServerName/func/test.bv2?testparam1=charlie" method="post">
  <label for="data1">Data 1:</label>
  <input type="text" id="data1" name="data1">
  <label for="data2">Data 2:</label>
  <input type="text" id="data2" name="data2">
  <input type="submit" value="Submit">
</form></p>
<p>This is a function called from location configuration for testing parameters.</p>
<p>GET parameter: testparam=.</p>
<p>Arguments: testparam1=charlie.</p>
<p>Method: POST.</p>
<p>Header count: 11.</p>
Header 0: Host = ServerName<br>
Header 1: User-Agent = Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:142.0) Gecko/20100101 Firefox/142.0<br>
Header 2: Accept = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br>
Header 3: Accept-Language = nb-NO,nb;q=0.9,no-NO;q=0.8,no;q=0.6,nn-NO;q=0.5,nn;q=0.4,en-US;q=0.3,en;q=0.1<br>
Header 4: Accept-Encoding = gzip, deflate<br>
Header 5: Referer = http://ServerName/<br>
Header 6: Content-Type = application/x-www-form-urlencoded<br>
Header 7: Content-Length = 22<br>
Header 8: Connection = keep-alive<br>
Header 9: Upgrade-Insecure-Requests = 1<br>
Header 10: Priority = u=4<br>
<p>Found 2 POST parameter(s)!</p>
<p>Length of POST section: 2136.</p>
<p>Found the following POST parameter(s):</p>
<p>Key 0: data2, Value 0: sdfsf.</p>
<p>Key 1: data1, Value 1: abcf.</p>
</body></html>

Regards Bent

 

TinyPortal © 2005-2018