GithubHelp home page GithubHelp logo

risoflora / brookframework Goto Github PK

View Code? Open in Web Editor NEW
230.0 29.0 52.0 794 KB

Microframework which helps to develop web Pascal applications.

Home Page: https://risoflora.github.io/brookframework

License: GNU Lesser General Public License v2.1

Pascal 97.97% Batchfile 0.20% Shell 0.55% CSS 1.29%
http iot pcre tls embedded delphi lazarus freepascal gzip rest

brookframework's Introduction

Brook framework

Support this project via PayPal GitHub releases License: LGPL v2.1

Overview

Brook is a cross-platform microframework which helps to develop web Pascal applications built by Delphi or Lazarus IDE and Free Pascal. Its core has been developed using the Sagui library, that's why it is so fast, compact and useful to run on embedded systems.

Features

  • Three threading modes:
    • Event-driven - single-thread + polling.
    • Threaded - one thread per request.
    • Polling - pre-allocated threads.
    • Isolated request - request processed outside main thread.
  • Fast path routing that supports:
    • Regular expression with JIT optimization.
    • Binary search for path entry-points.
  • HTTP compression:
    • Deflate - for static strings and streaming.
    • Gzip - for file compression.
  • HTTP cookies:
    • Providing classes which handles server side cookies.
  • HTTPS support:
    • Data encryption through GnuTLS library.
  • Dual stack:
    • IPv4 and IPv6 on top of a single socket.
  • Basic authentication:
    • For standard login using username and password.
  • Upload/download:
    • Static body and payload.
    • Content streaming for real-time applications.
    • Small and large files transferring.
  • Mathematical expression evaluator:
    • Arithmetic, bitwise and logical operators.
    • Variables allocation at build and/or run time.
    • Macro support to define functions at run time.
    • Extendable with custom functions.
    • Error handling with error kind and position.
  • Media types:
    • Resolving media types (MIME) in any supported platform.
  • Logging:
    • Allowing to generate logs in console or files.
  • String buffer:
    • For fast operations involving strings.
  • String map:
    • Hashed lists for key-value mapping.
  • And more:
    • Discover more features by playing with our examples.

Examples

The example below shows a minimal hello world HTTP server:

type
  THTTPServer = class(TBrookHTTPServer)
  protected
    procedure DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest;
      AResponse: TBrookHTTPResponse); override;
  end;

procedure THTTPServer.DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest;
  AResponse: TBrookHTTPResponse);
begin
  AResponse.Send('Hello world', 'text/plain', 200);
end;

begin
  with THTTPServer.Create(nil) do
  try
    Port := 8080;
    Open;
    if not Active then
      Exit;
    WriteLn('Server running at http://localhost:', Port);
    ReadLn;
  finally
    Free;
  end;
end.

There are other examples available in the Examples directory.

Downloading

All stable releases are available to download via GetIt, OPM and GitHub releases page.

We strongly recommend you to install Brook using GetIt or OPM, however, if you want to download the very latest source from the Git repository, do this:

git clone https://github.com/risoflora/brookframework.git

It will create a directory named brookframework filled with the source code.

Documentation

The documentation has been written in PasDoc and is available in HTML format at brookframework-docs.

Targets

Successfully tested on:

  • Windows
  • Linux
  • Raspbian/Android

compiled using:

  • Delphi XE family (Rio)
  • Lazarus / Free Pascal (Lazarus 2.0+ / FPC 3.2+)

Versioning

Starting from the version 1.0.0, Brook follows the SemVer rules regarding API changes with backwards compatibility across major releases.

Contributing

Brook framework is totally open source and would not be possible without our contributors. If you want to submit contributions, please fork the project on GitHub and send a pull request. You retain the copyright on your contributions.

Donations

Many open source projects, large and small, receive donations to encourage their authors, therefore, it would be not different in Brook.

All money collected from donations are invested to the purchase of study materials. This way, directly or indirectly, all knowledge acquired in the studies influence the spread of this project.

If you want to support this project, please choose one of the options below to make a donation.

Support this project via PayPal Support this project via PagSeguro

(For those who would like to donate in Brazilian BRL, it can be done by a identified bank deposit or via PayPal Brazil.)

Check the list of all donors that lovely supported this idea! ❤️

Community

Would you like to ask questions and talk to more Brook users?

Join us to the official group at Telegram and be welcome! :slightly_smiling_face:

Support

This project values being simple, direct and self-explanatory. However, if you need some help to integrate Brook to your application, we have the option of a paid consulting service. Contact us!

Projects using Brook

  • Brook Telegram - Telegram plugin for Brook framework. [MIT]
  • Aproveita.App - PWA application for supermarket products sales. [Comercial]
  • Client Web Portal - Application to manage appointments, update demographics, download previous invoices from the RUBI medical records system. [Commercial]

Would you like to add your project to that list above? Feel free to open a new issue requesting it! :-)

Licensing

Brook framework is released under GNU Lesser General Public License v2.1. Check the LICENSE file for more details.

brookframework's People

Contributors

al-muhandis avatar domenicomammola avatar gustavogalvan avatar silvioclecio avatar silvioprog avatar waldirpaim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

brookframework's Issues

EBrookHTTPServer: Failed to send data in request for ...

Hi @silvioprog !
BrookFramework 4.0 with sagui (legacy), http standalone server.
It is a question. How to handle this error?

Exception at 05279DA0: EBrookHTTPServer:
Failed to send data in request for `/someactionpage'.

I often have such errors on one of my projects with webhook. Today I noticed another more simple example with this errors and it is tested on local computer and debian web server:
For example, if you attach Ajax request (for click counting) to an anchor (<a></a>) click event, then there will be a similar error. That is, if the script make a delay before the direct jump to a new page, the error does not occur, but then the browser will try to read the Ajax response (although in my particular case it is not necessary), if the delay is removed, then the server has a similar error.

Simply I assume that a similar error occurs when the client does not read the server response for some reason. This situation may arise. How to process this request correctly? Could there be a memoryleak for this reason?

SendBytes method fails if content is an empty array

When using the SendBytes method to send a binary response it fails if ABytes argument is an empty array of bytes.

Steps to reproduce:

Run this program. It's inspired by hellohttpsrv.pas FPC example

program TestBrook;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this },
  BrookHTTPRequest,
  BrookHTTPResponse,
  BrookHTTPServer;

type
  THTTPServer = class(TBrookHTTPServer)
  protected
    procedure DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest;
      AResponse: TBrookHTTPResponse); override;
  end;

procedure THTTPServer.DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest;
  AResponse: TBrookHTTPResponse);

begin

  AResponse.SendBytes([], 0, 'application/octet-stream', 200);
end;

begin
  with THTTPServer.Create(nil) do
  try
    Port := 4000;
    Open;
    if not Active then
      Exit;
    WriteLn('Server running at http://localhost:', Port);
    ReadLn;
  finally
    Free;
  end;
end.

Raised error and/or generated log.

Invalid argument

Environment:

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Windows 10 and Ubuntu 20.04
  • Lazarus 2.0.12
  • Brook 5.4.7
  • Sagui 3.3.2 x86_64

PR: #32

Test project does not compile

The test project does not compile. Many errors.
Obviously, the test project has not been updated for a long time.

FPC 3.2+ support

Upgrade the sources to support FPC 3.2+ and drop support for very legacy compilers (<=3.1).

win11, lazarus, brookframework, libsagui-3.dll with tls doesn't work?

I tried to build the demo project of brookframework/Examples/Console/FPC /hellohttpsrv.lpr with lazarus v3.0 on win11 and having libsagui-3.dll(tls_win_amd64 version) in the project folder.

An error happend with the message: libsagui-3.dll is not loaded. It happened in libsagui.pas, line 1014: GHandle := SafeLoadLibrary(AName); GHandle is 0 after calling the SafeLoadLibrary function.

I tried to put the libsagui-3.dll file in project folder and/or windows/system32. But I always got that error.

I then download libsagui-3.5.0-windows_amd64.zip and put the libsagui-3.dll without tls in the project folder. The program works!

Something wrong when load libsagui tls_win_amd64 version dll?

image
image

Support HTML multipart/form-data form submit

Hello

I am using Delphi 10.2 in the Examples of httpuploads. I tested it and found that it seemed to support only files, not text。。

For example, I added < input type = "text" name = "user" >, but I couldn't get the value of user in the DoRequest event.
aa

ARequest.Params seems that only supported forms with the application / x-www-form-urlencoded attribute。

How can I get the value of user?

Thank you

Static file resolver

It would be nice to write a component to provide static files with caching support (at least via ETag).

Automatic download of the Sagui library

Hi.

It would be nice if Brook could download Sagui library automatically and save it into the user directory. The feature could be implemented in a new component, something like:

BrookLibraryDownloader::Active::Boolean | Default: True
BrookLibraryDownloader::Version::String | Default: latest Sagui release
BrookLibraryDownloader::Directory::String | Default: ~/.sagui/lib

This way, the BrookLibraryLoader could be updated to find the library also in BrookLibraryDownloader::Directory::String.

cheers,

When thread=false and poolsize=8 are set, the server will process the requests in order under the multi-threaded request? If I want the poolsize situation, can the server respond to threads concurrently?

program brookserver;

{$APPTYPE CONSOLE}
{$R *.res}

uses
SysUtils, Classes, BrookUtility, BrookHTTPRequest, BrookHTTPResponse,
BrookHTTPServer, BrookURLRouter, System.Threading, System.Diagnostics,
System.Net.URLClient,
System.Net.HttpClient, System.Net.HttpClientComponent;

type
TRouteTime = class(TBrookURLRoute)
protected
procedure DoRequest(ASender: TObject; ARoute: TBrookURLRoute;
ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse); override;
public
procedure AfterConstruction; override;
end;

TIdBrookHttpServer = class(TBrookHTTPServer)
protected
FRouter: TBrookURLRouter;
fThreadCount: Integer;
procedure DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest;
AResponse: TBrookHTTPResponse); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure RegisterRouter(const PortValue: Integer;
const threadcount: Integer; const usethread: Boolean = false); virtual;
function Start: Boolean; virtual;
procedure Stop;
end;

{ TsdBrookHttpServer }

constructor TIdBrookHttpServer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FRouter := TBrookURLRouter.Create(Self);
end;

destructor TIdBrookHttpServer.Destroy;
begin
FRouter.Free;
inherited Destroy;
end;

procedure TIdBrookHttpServer.DoRequest(ASender: TObject;
ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse);
begin
FRouter.Route(ASender, ARequest, AResponse);
end;

procedure TIdBrookHttpServer.RegisterRouter(const PortValue,
threadcount: Integer; const usethread: Boolean = false);
begin
TRouteTime.Create(FRouter.Routes);
Port := PortValue;
fThreadCount := threadcount;
Threaded := usethread;
end;

function TIdBrookHttpServer.Start: Boolean;
begin
Threaded := false;
if Threaded = false then
begin
if fThreadCount <= 1 then
begin
if TThread.ProcessorCount > 1 then
begin
ThreadPoolSize := TThread.ProcessorCount
end
else
begin
ThreadPoolSize := 4;
end;
end
else
ThreadPoolSize := fThreadCount;
end;
ConnectionLimit := 10000;
NoFavicon := true;
FRouter.Active := true;
Open;
Result := Active;
end;

procedure TIdBrookHttpServer.Stop;
begin
Active := false;
end;

{ TRouteTime }

procedure TRouteTime.AfterConstruction;
begin
Methods := [rmGET];
Pattern := '/time';
end;

procedure TRouteTime.DoRequest(ASender: TObject; ARoute: TBrookURLRoute;
ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse);
var
time: string;
begin
sleep(3000);
time := FormatDateTime('YYYY-MM-DD hh:mm:ss', Now);
AResponse.Send('return datetime:' + time, 'text/plain;charset=utf-8', 200);
end;

var
PoolServer, ThreadServer: TIdBrookHttpServer;
tasks: array of ITask;
I: Integer;
StopWatch: TStopwatch;

begin
try
{ TODO -oUser -cConsole Main : Insert code here }
PoolServer := TIdBrookHttpServer.Create(nil);
ThreadServer := TIdBrookHttpServer.Create(nil);
try
PoolServer.RegisterRouter(9001, 8);
if PoolServer.Start then
writeln('Pool Service is Starting...Port:9001.url:http://127.0.0.1:9001/time');
ThreadServer.RegisterRouter(9002, 8, true);
if ThreadServer.Start then
writeln('Thread Service is Starting...Port:9002.url:http://127.0.0.1:9002/time');
SetLength(tasks, 4);
StopWatch := TStopwatch.StartNew;
for I := 0 to Length(tasks) - 1 do
begin
tasks[I] := TTask.Create(
procedure
var
client: TNetHTTPClient;
Res: IHTTPResponse;
begin
client := TNetHTTPClient.Create(nil);
try
Res := client.Get('http://127.0.0.1:9002/time');
writeln('<9002 Result>' + Res.ContentAsString());
finally
client.Free;
end;
end);
tasks[I].Start;
end;
TTask.WaitForAll(tasks);
StopWatch.Stop;
writeln('Thread Server:' + StopWatch.ElapsedMilliseconds.ToString
+ '(ms)');
StopWatch.Reset;
StopWatch.Start;
for I := 0 to Length(tasks) - 1 do
begin
tasks[I] := TTask.Create(
procedure
var
client: TNetHTTPClient;
Res: IHTTPResponse;
begin
client := TNetHTTPClient.Create(nil);
try
Res := client.Get('http://127.0.0.1:9001/time');
writeln('<9001 Result>' + Res.ContentAsString());
finally
client.Free;
end;
end);
tasks[I].Start;
end;
TTask.WaitForAll(tasks);
StopWatch.Stop;
writeln('Pool Service:' + StopWatch.ElapsedMilliseconds.ToString
+ '(ms)');
readln;
finally
PoolServer.Stop;
PoolServer.Free;
ThreadServer.Stop;
ThreadServer.Free;
end;
except
on E: Exception do
writeln(E.ClassName, ': ', E.Message);
end;

end.

brookserver

[
testbrookserver.zip
](url)

Unable to prevent browsers from connecting with less security than TLS 1.2

Without this, some browsers will disallow connection to your website. They will report your website as a security risk.

Steps to reproduce:

In your Brook Framework project, create an TBrookHTTPServer.OnRequest event. Add the code shown below. Run the app and start the TBrookHTTPServer. Start your browser and make a request from your Brook app. A SEGSEV error is displayed at the line indicated below.

`procedure TfrmMain.brk_svrRequest(ASender: TObject; ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse);
var idx: Integer; pth, fnm: String;
begin
// Attempt to clamp down on TLS 1.0 and 1.1
if Assigned(ARequest.TLSSession) then
begin
gnutls_set_default_priority(ARequest.TLSSession); // <-- SIGSEV here
end;

brk_rtr.Route(ASender, ARequest, AResponse);
end;
`

Environment:

Windows Server 2016, Lazarus 2.0.10 FBC 3.2.0,, Brook 5 Framework 5.5.0.0, libsagui 3.3.3.0, gnutils 3.6.15

can not compile for Delphi Tokyo 10.2 - 10.2.3 under Linux (System.Contnrs not allowed)

Hello in Delphi 10.2 - 10.2.3 there is a problem under Linux that "System.Contnrs" is not accepted. The exchange of "System.Contnrs" with "System.Generics.Collections" solves the problem.

Environment:

  • Linux (Debian 10.5 Console)
  • Delphi 12.2.3
  • Brook 5.1.0
  • Sagui 3.1.3 Linux
In the code the following code : 

  TSgUnloadEvents = class sealed
  private
    FCS: TCriticalSection;
    FList: TObjectList;
  protected
    property CS: TCriticalSection read FCS;
    property List: TObjectList read FList;

convert to :

  TSgUnloadEvents = class sealed
  private
    FCS: TCriticalSection;
    FList: TObjectList<TSgLibUnloadHolder>;
  protected
    property CS: TCriticalSection read FCS;
    property List: TObjectList<TSgLibUnloadHolder> read FList;


change Constructor Code  :

constructor TSgUnloadEvents.Create(ACS: TCriticalSection);
begin
  inherited Create;
  if not Assigned(ACS) then
    raise EArgumentNilException.CreateFmt(SParamIsNil, ['ACS']);
  FList := TObjectList.Create;

convert to :

constructor TSgUnloadEvents.Create(ACS: TCriticalSection);
begin
  inherited Create;
  if not Assigned(ACS) then
    raise EArgumentNilException.CreateFmt(SParamIsNil, ['ACS']);
  FList := TObjectList<TSgLibUnloadHolder>.Create;

Unfortunately the class "TSgLibUnloadHolder" has to go up as well.

PS: After this conversion, it works wonderfully.

Requesting a way to easy disable the global locker for threaded applications

About this commit (c2189d6) . My threaded web server (it has the code

... ... ...
{$DEFINE THREADED}

uses
{$IF DEFINED(UNIX) AND DEFINED(THREADED)}
  CThreads,
{$ENDIF}
... ... ... ... ...
begin
  {$IFDEF THREADED}
  Application.Server.Threaded := True;
  {$ENDIF}   
... ... ...

) stop being threaded after the commit (Made the server thread safe.).

(this is the brook4freepascal via brookframework app)

Is there a way to easy disable the global locker for threaded applications

CI

A Continuous Integration would be really very welcome. 🙂

Error during select (9): `Bad file descriptor'

What kind of bug could it be? Where can I find information?

[EBrookHTTPServer] Error during select (9): `Bad file descriptor'

Second error (other times):

Fatal error in GNU libmicrohttpd /root/libsagui-3.4.1/lib/libmicrohttpd-0.9.76/src/microhttpd/daemon.c:3845: Close socket failed.

I localized an interesting point. The error sometimes occurs if the FCL httpclient is used in one of the worker threads. If the client in the thread does not cause such errors never occurs

Thanks

In BrookHTTPCookies in Line 278 "VEncoder.Destroy;" do not work under Linux

In Windows the Compiler accept the line 278 "VEncoder.Destroy;" but not the Linux compiler.
you need to use Free or DisposeOf here.

[DCC Fehler] BrookHTTPCookies.pas(278): E2362 Auf protected-Symbol TObject.Destroy kann nicht zugegriffen werden

Environment:

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Linux
  • Delphi 10.2.x
  • Brook 5.4.1
  • Sagui 3.3.0 x86_64

Media types

Hello,

it would be nice to implement a tiny media types support. For example, some parser to use the mime.types media base.

can not compile using delphi tokyo 10.2

[dcc32 Error] BrookUtility.pas(55): E2003 Undeclared identifier: 'tkMRecord'
[dcc32 Error] BrookUtility.pas(56): E2026 Constant expression expected
[dcc32 Fatal Error] BrookHTTPCookies.pas(73): F2063 Could not compile used unit 'BrookUtility.pas'
Failed

Primitive kinds in BrookUtility (5.2.0) Compiler Version to low

In Line 56 the Compiler Version is to low.
"[tkClassRef..{$IF CompilerVersion >= 32.0}tkMRecord{$ELSE}tkProcedure{$ENDIF}]"

You can fix it by change the Compiler Version to 33.0 . I have it with 10.2.1 tested and it works.

Environment:

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Windows
  • Delphi 10.2.1
  • Brook 5.2.0

More documentation

Hello,

many Brook users are requesting more documentation, so we should write it (and more examples, tests etc.) before releasing Brook Tardigrade. This related note was added here.

sincerely,

Application crashes when it is being closed

Hello,

To reproduce it, just:

  • open the HTTPServer_Example.dproj, build/run and click "Start";
  • close the application.

it will crash dumping the following stack log:

HTTPServer_frMain.TfrMain.UpdateControls
HTTPServer_frMain.TfrMain.BrookHTTPServer1Stop($3A47D90)
BrookHTTPServer.TBrookHTTPServer.DoClose
BrookHTTPServer.TBrookHTTPServer.SetActive(False)
BrookHTTPServer.TBrookHTTPServer.Close
BrookHTTPServer.TBrookHTTPServer.UnloadLibCb($3A47D90)
libsagui.SgLib.CallUnloadCbs
libsagui.SgLib.Unload
BrookLibraryLoader.TBrookLibraryLoader.Close
BrookLibraryLoader.TBrookLibraryLoader.Destroy
System.TObject.Free
System.Classes.TComponent.DestroyComponents
System.Classes.TComponent.Destroy
FMX.Types.TFmxObject.Destroy
FMX.Forms.TCommonCustomForm.Destroy
FMX.Forms.TCustomForm.Destroy
System.TObject.Free
System.Classes.TComponent.DestroyComponents
FMX.Forms.DoneApplication
System.SysUtils.DoExitProc
System._Halt0

Access Violation (C0000005)

After calling the URL, the program stops with an access violation (C0000005) when calling against TBrookHTTPResponse.IsEmpty (sg_httpres_is_empty).

Steps to reproduce:

use your own excemple Project and run the urlrouter.exe.
Use the given URL and Port and wait a sec. then the Application Crash with AV C0..05.

Environment:

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Windows
  • Delphi 10.2.1
  • Brook 5.2.0
  • Sagui 3.2.0 x86_64

HTTPServer under linux 64 Ubuntu

Testing performance of provided HTTPServer example with weighttp in linux eventually results in "error: connect() failed: Cannot assign requested address (99)" Whereas same test against NGinx on same machine doesn't fail.

Running following test few times will see responses of HTTPServer eventually slow until errors occur.
weighttp -n 10000 -t 5 -c 5 http://192.168.0.57:1080

Note I am running Mint Mate in VirtualBox on a Core i7-3770.

The results from HTTPServer example when working are 8000+ req/s. Not as fast as nginx 13000 req/s but impressive never-less. It seems Sagui library isn't releasing ports (lazy release) as fast as nginx so weighttp cannot connect to the server. Note that I have run much larger test against NGinx (-n 100000) and it still doesn't fail so don't think its an OS issue.

Thanks Glen

Client Web Portal for RUBI Medical Records System

Project Name: CWP (Link withheld) Description: The RUBI medical records system is built for large busy clinics, that own or fully control their server(s). Clinic patients can use the CWP to manage appointments, update demographics, download previous invoices or download their medical history. This project is not a stand alone project, it only works with the RUBI Medical Records System. The CWP is a high performance Microsoft Windows executable, using the REST server model, built using the Brook 5 Framework.

Message and/or error suppression or callback function

Hello,

for better usability I think a feature to suppress libsagui messages and/or errors or forward them to a callback function would be very nice.

For example when the port is not free the libsagui dll shows error message, instead of raise some specific exception or call an OnError callback, or something can be handled by the caller application.

In Threading mode URL Router "Freezes" on 404 or "/"

Maybe I found the problem in BrookURLRouter.pas, in procedure TBrookURLRouter.Route.
I put two FLocker.Unlock, one in line 102 after R.HandleRequest(..., and the other at the end, before DoNotFound(...

This is the code fragment:

  if B then
  begin
    DoRoute(ASender, APath, ARequest, AResponse);
    Exit;
  end;
  if APath = '/' then
  begin
    R := FRoutes.FindDefault;
    if Assigned(R) then
    begin
      R.HandleRequest(ASender, R, ARequest, AResponse);
      FLocker.Unlock; {bugfix?}
      Exit;
    end;
  end;
  DoNotFound(ASender, APath, ARequest, AResponse);
  FLocker.Unlock; {bugfix?}
end;

I hope this help.
Thank for your great job !

TextArea length overrun

extra_chars
A clear and concise description of what the bug is.

Steps to reproduce:

  1. Create a FORM web page that has a <textarea> some text </textarea> pair of tags
  2. Use Brook 5 Framework functions ARequest.Fields.TryValue() to save the contents to a variable
  3. There will always be some random garbage characters at the end of the field

Example is attached.

Environment:

Windows Server 2016, Lazarus 2.0.10, FPC 3.2.0, and Brook 5 Framework 5.5.0.0
libsagui 3.3.3.0

TEXTAREA_BUG.zip

where_to_add_text

First request fails on Windows when gzip is enabled

Hello.

Just try to send any file and try to get it via any HTTP client. On Postman, it reports:

Could not get any response

There was an error connecting to http://localhost:8080/axios.min.js.

Why this might have happened:

  The server couldn't send a response:
  Ensure that the backend is working properly
  Self-signed SSL certificates are being blocked:
  Fix this by turning off 'SSL certificate verification' in Settings > General
  Proxy configured incorrectly
  Ensure that proxy is configured correctly in Settings > Proxy
  Request timeout: Change request timeout in Settings > General

Thank you!

TBrookLogger

A logging component would be very welcome. :-)

Dockerizing with Alpine Linux needs pseudo-tty allocation by '-it' option to 'docker run'

Environment:

  • Host is Xubuntu 20.04
  • FPC 3.2.0
  • Lazarus 2.0.10
  • libsagui is built from source cloned from the repo, master branch, last commit 67c1aae556b9bd86d3eb36a949ce98f944adc69f
  • Brook is clone of this repo, master branch, last commit 7724382
  • Program is Examples/Console/FPC/hellohttpsrv.lpr
  • libsagui, Brook and the Hello program are built on Ubuntu host
% ls -l
total 1968
-rw-r--r-- 1 pierce pierce     307 Aug 15 08:33 Dockerfile
-rwxrwxr-x 1 pierce pierce 1104056 Aug 15 08:53 hellohttpsrv*
-rwxr-xr-x 1 pierce pierce  901816 Aug 15 00:32 libsagui.so.3*

Program works on command line:

% LD_LIBRARY_PATH=`pwd` ./hellohttpsrv
Server running at http://localhost:8080

In another terminal window:

% curl http://127.0.0.1:8080
<html><head><title>Hello world</title></head><body>Hello world</body></html>%    

Dockerfile:

% cat Dockerfile
FROM alpine:3.12
RUN apk --no-cache --update add libc6-compat
WORKDIR /app
COPY hellohttpsrv /app/helloworld
COPY libsagui.so.3 /lib/libsagui.so.3
RUN addgroup -g 1099 apprunner \
  && adduser -D -u 1099 -G apprunner -h /home/apprunner apprunner
USER apprunner:apprunner
EXPOSE 8080
CMD ["/app/helloworld"]

Build and tag as helloworld:brook4:

% sudo docker build -t helloworld:brook4 .
...
Successfully tagged helloworld:brook4

The resulting Docker container exits immediately though:

% sudo docker run --rm -p 8080:8080 helloworld:brook4 
Server running at http://localhost:8080
% 

But running the Docker container interactively (by using -it option and running sh) works:

% sudo docker run -it --rm -p 8080:8080 helloworld:brook4 sh
/app $ ls -l
total 1080
-rwxrwxr-x    1 root     root       1104056 Aug 15 00:53 helloworld
/app $ ./helloworld
Server running at http://localhost:8080

In another terminal window:

% curl http://127.0.0.1:8080            
<html><head><title>Hello world</title></head><body>Hello world</body></html>%

And running with -it option to docker run works too:

% sudo docker run -it --rm -p 8080:8080 helloworld:brook4
Server running at http://localhost:8080

In another terminal window:

% curl http://127.0.0.1:8080            
<html><head><title>Hello world</title></head><body>Hello world</body></html>%

Not sure if this counts as a bug; I've not encountered the need to use '-it' option when dockerizing other server-type programs.

Reference: My posts to Lazarus forum that also talk about fcl-web and BrookFreePascal that have pure Pascal HTTP servers.

Support for RAD / Delphi 11 (Alexandria)

Hi,
I have seen that the Brook framework is no longer in the GitManager in Studio version 11. After changing the filename Platform to BrookPlatform, I was able to install and work with Brook-Framework with RAD Studio 11.

/Regards

Environment:

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Windows / Linux
  • Delphi 11
  • Brook 5.5.0

REST & SQLite3 & Vue.js

Hello.

It would be nice to add a simple to-do list-like application (classical TodoMVC?) showing how to integrate Brook with SQLite3 and some popular JavaScript frameworks like Vue.js.

Thank you!

SSE support

Hi.

It would be nice to implement SSE support, very useful to create real time applications.

cheers

ref: sagui#43

One route cannot be a subset of another route

A clear and concise description of what the bug is.

Steps to reproduce:

  1. Create a route with a pattern like this: /apt_tdy_msg_q
  2. Create another route that has a pattern that is a subset of the first pattern, like this: /apt_tdy
  3. Result: Compiler may, or may not complain. If it does not complain...
  4. At run time, Brook Server component will hang on attempt to start

Environment:

Windows Server 2016, Lazarus 2.0.10 FBC 3.2.0,, Brook 5 Framework 5.5.0.0, libsagui 3.3.3.0

I am perhaps in the wrong for using underscores in my patterns. I am a beginner with Brook 5 Framework. I probably shd be using slashes instead.

TBrookHTTPUploadsEnumerator weird behaviour under linux (Ubuntu 24.04)

Hello,
I have a microserver built with Brookframework (main branch updated 26-06-2024) and libsagui 3.5.0.
I've tested it under Windows 11 and Ubuntu 24.04 too.

I've used an instance of TBrookHTTPUploadsEnumerator class to retrieve the files uploaded by the client (react web app).

When the user uploads 2 or more files the following cycle works only if the server is under Windows:

upldEn := ARequest.Uploads.GetEnumerator; repeat [code that uses upldEn.Current] until upldEn.MoveNext;

In linux upldEn.MoveNext returns true immediately, so in linux I can't use the enumerator.

I found that this code instead is working fine in linux:

for i := 0 to ARequest.Uploads.Count - 1 do begin if i = 0 then upld := ARequest.Uploads.First else upld := ARequest.Uploads.Next; [code that uses upld] end;

Environment:

OS, compiler and Brook version to reproduce the problem:

  • Windows 11 / XUbuntu 24.04
  • Lazarus 3.2 FPC 3.2.2
  • Brook 5.7.0
  • Sagui 3.5.0 x86_64 windows/linux

Is this a bug or I am doing something wrong?
Thanks in advance and thanks for the beautiful framework,

Domenico

JChat for FireFox

A chat app meant to run on any browser. It's purpose is for internal "chat" type communication amongst members of a small team. Although the obvious choice for this situation is Server Side Events, SSE has such severe limitations in both the server and the browser (6 instances), simple polling was used instead. Brook 5 Framework is so efficient, handling thousands of unnecessary (as in "no new messages to send") polling events is easy. A JavaScript interval of 3 seconds is used to poll the server and get updates of which other users are active, inactive or idle, as well as a list of new conversations, or new messages. Each conversation opens in it's own tab, and each message includes a face photo of the other user. All HTML and Javascript is dead simple and from W3 Schools. No libraries were used.

Interesting "Behind the scenes" Facts:

SSE Limitations: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
About the name: This app replaces a stand-alone windows executable chat app that was built in Delphi XE3 that was in use in our company for about 8 years prior. Having "For FireFox" helped users differentiate this app from the old Windows-only app.

Brook 5 Framework was the perfect fit for this situation.

Isolated thread is unable to .Send FreePascal only

I'm building a Brook 5 Framework app, in which, some of the threads will be very slow to execute, so they need to be isolated. I am able to compile, but the isolated thread always returns a "Response already sent." error message, instead of the response HTML I want to send. If not isolated, the procedure works correctly and returns the desired HTML page.

I have included other lines of code, not related to this issue, from the top of the unit, just to get you oriented:

...
private
procedure BlahBlah;
public
end;

// This is the procedure that is isolated
procedure ReportAllInvoices(ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse; AUserData: Pointer);

var
frmMain: TfrmMain;

implementation
...

procedure TfrmMain.brk_rtrRoutes38Request(ASender: TObject; ARoute: TBrookURLRoute; ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse);
begin
// Download All Invoices (Isolated)
ARequest.Isolate(@ReportAllInvoices);
end;

// -------- Isolators

procedure ReportAllInvoices(ARequest: TBrookHTTPRequest; AResponse: TBrookHTTPResponse; AUserData: Pointer);
begin
AResponse.Send('Hello', 'text/html; charset=utf-8', 200); //<-- The user sees "Response already sent" instead of "Hello"
end;

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Windows Server 2016
  • Lazarus
  • Brook 5.4.9
  • Sagui 3.3.3 (TLS version) x86_64

Threaded property doesn't work on Delphi

Using the framework on Delphi, if we check the property Threaded, the server aborts after a few seconds of stresstest
On Lazarus, if we uncheck that property it performs better than with it. But on Delphi it HAS to be toggled off.

Tests were done with the server exe running on windows server 2019 STD v1809 with 4 threads, 4GB RAM i3-4150
and the test client was Apache jMeter.
Test parameters are: 150 concurrent requests per second over 30 seconds no http, simple ping/pong test

Brook version was the latest available here on master, downloaded today 11h ago.
libsagui is the latest release 3.5.0 amd64
Delphi version tested is 12.0 without patch 1
Lazarus version is 3.0

Delphi:
image

Lazarus with Threaded
image

Lazarus without Threaded
image

Easy alternative to ZSend()-like methods

Hello,

the ZSend()-like methods aren't intuitive, so it would be nice some algorithm which could decide automatically to compress the response based in the client's Accept-Encoding header, or at least something like this:

begin
  AResponse.Compressed := True;
  AResponse.Send(... Params ...);
...

or, in a more global way:

BrookHTTPServer1.Compression := hcGzip;

Thanks!

dcc32 Fatal Error in BrookMathExpression.pas with D 10.2.1

When you create the BrookFramework, you get a Fatal Error. ([dcc32 Fatal Error] BrookMathExpression.pas(492): F2084 Internal Error: C20339)
But the problem is in line 485 "FExtensionsHandle[FExtensions.Count] := Default(sg_expr_extension);"
If I Uncommenting this line, the project compiles.
On the quick, however, I could not determine what problem he has here.

Environment:

OS, compiler and Brook version to reproduce the problem, e.g.:

  • Windows
  • Delphi 10.2.1
  • Brook 5.1.x and 5.2.0
  • Sagui 3.1.x x86_64 and 3.2.x

M.ToCString() has a bug

If the parameter is a double-byte string(E.g. Chinese), the function will return a garbled string.

Steps to reproduce:

TestCode:

procedure THTTPServer.DoRequest(ASender: TObject; ARequest: TBrookHTTPRequest;
AResponse: TBrookHTTPResponse);
begin
//Path contains Chinese
AResponse.Download('G:\编程\TestFiles\1.txt');
end;

Open the browser and it will prompt File not found, click the breakpoint on the function sg_httpres_download, you will find that the variable filename is garbled

1

2

Environment:

  • Windows 10 Enterprise
  • Delphi 10.2
  • Brook 5.4.7
  • Sagui 3.3.1 x86

In fact, PAnsiChar(AnsiString(AFileName)) can be used to solve this problem.

procedure TBrookHTTPResponse.Download(const AFileName: TFileName;
AStatus: Word);
var
M: TMarshaller;
R: cint;
begin
SgLib.Check;
if FCompressed then
begin
R := sg_httpres_zdownload(FHandle, PAnsiChar(AnsiString(AFileName)), AStatus);
CheckZLib(R);
end
else
R := sg_httpres_download(FHandle, PAnsiChar(AnsiString(AFileName)), AStatus);
CheckAlreadySent(R);
if R = ENOENT then
raise EFileNotFoundException.Create(SFileNotFound);
SgLib.CheckLastError(R);
end;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.