Monday, December 31, 2012

Brook Framework, a new web application framework for Free Pascal

Recently, a new post in Lazarus forum surprised me. Somebody, OK, Silvio, announced his new web application framework for Free Pascal with over 15000 lines of code written, having integration with the great Greyhound data access framework, named Brook Framework. OK, so what's interesting from this framework? Keep reading.

Architecture: routes, actions and methods

Even though it's built on top of fcl-web, it doesn't make use of fcl-web architecture. Brook uses the concept of routes as commonly found in frameworks for other programming languages. For each request path (that /something/and/probably/longer thing) you want to support, you register a class (TBrookAction descendant) to handle the request path. The class itself implements method for each HTTP method the class will support (commonly GET and POST, but other methods like HEAD and PUT are also supported). This is, IMHO, a more structured yet flexible way than module-action architecture as used by fcl-web. FYI, the module-action architecture has a hardcoded request path in the form of /module/action or ?module=module-name&action=action-name. This makes the request path difficult to be made search engine friendly because you have to pass additional parameters via param1=value1&param2=value2&param3=value3 and so on. OTOH, Brook allows you to register path in almost free form (taken from TBrookAction.Register documentation):

* - Allows any path. Example:

TMyAction.Register('*');

Can be called as http://localhost/cgi-bin/cgi1, http://localhost/cgi-bin/cgi1/foo/ etc;

/ - Adds an slash to the end of the URL if does not exist. Example:

TMyAction.Register('/foo/');

Can be called as http://localhost/cgi-bin/cgi1/foo or http://localhost/cgi-bin/cgi1/foo/. When called as http://localhost/cgi-bin/cgi1/foo, it will automatically redirected to http://localhost/cgi-bin/cgi1/foo/. If the pathinfo is different from /foo a 404 page is returned;

: - Creates variables URL. Their values can be read from the property Values. Example:

TMyAction.Register('/foo/:myvar');

Creates the "myvar", that can be read from the property Values, e.g:

Write(Values['myvar'].AsString);

NOTE: Two actions can't be registered with the same pattern except when they are called by means of different HTTP methods.

Data access integration

Actions could optionally have direct data access. To do that, the action must descend from TBrookDBAction instead of TBrookAction. The action could then read/write data from/to database (or something else) while serving a request. Actually, my experience in a good MVC structure teaches me not to tie the request handler and the data persistence layer. But since this is optional in Brook, I can live with it. Besides, it can be a good thing for quick development.

Enough talk...

So let's get started, we'll be using Lazarus for easiness.

  1. Download brook here
  2. Extract it somewhere, open packages/brookex.lpk with Lazarus and install, this will register entries for easily creating new brook projects in Project->New Project menu
  3. Next, pick up one of the available data access backends. Since I'm currently playing a lot with Greyhound, I pick up brookgreyhoundrt.lpk. You may pick something else if you like such as ZEOS or ADS backend.
  4. After Lazarus restart, pick Project->New Project menu, you'll see 2 new entries named "Simple CGI Application" and "Full CGI / FastCGI Application". Pick up the latter as it provides more features
  5. A dialog with form will appear, the fields are intuitive so I guess I don't have to explain. Just fill the form and press Next
  6. Another dialog will appear. Here you can set the actions you want and their respective path, optionally setting which one will be the default (if no specific path given the request). There's a button "Patterns help" that redirects to TBrookAction.Register documentation exactly like in the previous section. When you're done, press Next
  7. Congratulations! Simply skip (doh)
  8. A project will be created with one unit per action you register, and a bunch of predefined files: 404.html, 500.html, Brokers.pas and the .lpr. The most important file is Brokers.pas. This unit acts as a central configuration settings. So, whatever configuration you need, set it here. You'll see that it already registers the 404 and 500 page. For FastCGI application, you can set port here by using:
    TBrookFCGIApplication(BrookApp.Instance).Port := {Your port number here};
    
    Don't forget to add BrookApplication and BrookFCLFCGIBroker to the uses clause
  9. Now open up an action unit and you'll see the Get method is already overriden with a default content. You can edit that later to produce html or whatever output you want. For now, we just want to test that it works
  10. Build the project and run (in case of FastCGI) or copy to your webserver's cgi directory (in case of CGI)
  11. Now go to your browser and type the url to your application, I personally use FastCGI with Nginx on port 8080, and if my action is /index/, I'll type in my browser: http://localhost:8080/index/
  12. If you see your output, then you've managed to make it work. Feel free to improve
  13. Pascal for web? Why not? ;)

Sunday, June 24, 2012

Encryption / Decryption and Asynchronous Socket Programming


Back again, it's been a long time since my last post due to lack of free time and laziness :p

Recently, I've got some posts in Lazarus / Free Pascal forums asking for some incompletely documented features, namely the (en|de)cryption unit (blowfish) and asynchronous socket (from fcl-net). Free Pascal is shipped with huge powerful libraries which are mostly, unfortunately, undocumented. Through this post, I hope I can help document it a bit through examples (I'm still lazy for real documentation commit :p). Let's start, shall we?

Blowfish, the cryptography unit

current documentation: http://www.freepascal.org/docs-html/fcl/blowfish/index.html

This unit implements encryption / decryption classes with keys, and is able to apply it on any TStream descendant. For easiness, we'll use TStringStream for the example. On to the code:

{$mode objfpc}{$H+}

uses
  Classes,
  BlowFish;

var
  en: TBlowFishEncryptStream;
  de: TBlowFishDeCryptStream;
  s1,s2: TStringStream;
  key,value,temp: String;
begin
  { 1 }
  key := 'testkey';
  value := 'this is a string';
  { 2 }
  s1 := TStringStream.Create('');
  en := TBlowFishEncryptStream.Create(key,s1);
  { 3 }
  en.WriteAnsiString(value);
  en.Free;
  WriteLn('encrypted: ' + s1.DataString);
  { 4 }
  s2 := TStringStream.Create(s1.DataString);
  s1.Free;
  { 5 }
  de := TBlowFishDeCryptStream.Create(key,s2);
  { 6 }
  temp := de.ReadAnsiString;
  WriteLn('decrypted: ' + temp);
  
  de.Free;
  s2.Free;
end.

Explanations per curly brackets:

  1. First, we prepare the key (key) and data to be encrypted (value)
  2. Next, we create a TBlowFishEncryptStream instance, providing the key and stream to write the encrypted data into (s1)
  3. Now we write the unencrypted data. For testing, we output the encrypted data. You'll see that it would be a bunch of weird bytes
  4. Next, we will try to decrypt the data back to its original form. First, we create another TStringStream, this time we give the encrypted data as the stream data
  5. Then we create a TBlowFishDeCryptStream instance, providing the key that was used to encrypt the data and the stream from which the encrypted data would be read
  6. Next, read the data and output it. You'll see it's the original 'this is a string'
So easy, huh? On to the next one.

fcl-net, the undocumented treasure

current documentation: err.. none

This package offers a lot of networking things: asychronous socket, dns resolver, HTTP servlet, socket streams, etc. We would concentrate only on the asychronous socket (and implicitly, socket streams). At first glance, it looks uneasy to use. I have to dig in the sources to see how it works and guess how to use it. We will implement a server with multiple client support. To stay focus, the client will only connect, send a 'hello' message, then disconnects. The server would display notification for an incoming connection, the message sent by the client, and when the client disconnects. The server can only be terminated with Ctrl+C. Jump in to the server code:

{$mode objfpc}{$H+}

uses
  { 1 }
  {$ifdef unix}cthreads,{$endif}
  Classes,SysUtils,Sockets,fpAsync,fpSock;

type
  { 2 }
  TClientHandlerThread = class(TThread)
  private
    FClientStream: TSocketStream;
  public
    constructor Create(AClientStream: TSocketStream);
    procedure Execute; override;
  end;
  { 3 }
  TTestServer = class(TTCPServer)
  private
    procedure TestOnConnect(Sender: TConnectionBasedSocket; AStream: TSocketStream);
  public
    constructor Create(AOwner: TComponent); override;
  end;
{ 4 }
function AddrToString(Addr: TSockAddr): String;
begin
  Result := NetAddrToStr(Addr.sin_addr) + ':' + IntToStr(Addr.sin_port);
end;

{ TClientHandlerThread }
{ 5 }
constructor TClientHandlerThread.Create(AClientStream: TSocketStream);
begin
  inherited Create(false);
  FreeOnTerminate := true;
  FClientStream := AClientStream;
end;
{ 6 }
procedure TClientHandlerThread.Execute;
var
  Msg : String;
  Done: Boolean;
begin
  Done := false;
  repeat
    try
      Msg := FClientStream.ReadAnsiString;
      WriteLn(AddrToString(FClientStream.PeerAddress) + ': ' + Msg);
    except
      on e: EStreamError do begin
        Done := true;
      end;
    end;
  until Done;
  WriteLn(AddrToString(FClientStream.PeerAddress) + ' disconnected');
end;

{ TTestServer }
{ 7 }
procedure TTestServer.TestOnConnect(Sender: TConnectionBasedSocket; AStream: TSocketStream);
begin
  WriteLn('Incoming connection from ' + AddrToString(AStream.PeerAddress));
  TClientHandlerThread.Create(AStream);
end;
{ 8 }
constructor TTestServer.Create(AOwner: TComponent);
begin
  inherited;
  OnConnect := @TestOnConnect;
end;

{ main }
{ 9 }
var
  ServerEventLoop: TEventLoop;
begin
  ServerEventLoop := TEventLoop.Create;
  with TTestServer.Create(nil) do begin
    EventLoop := ServerEventLoop;
    Port := 12000;
    WriteLn('Serving...');
    Active := true;
    EventLoop.Run;
  end;
  ServerEventLoop.Free;
end.

It's a bit long, so take a breath:

  1. We will need each client to be handled in its own thread, so we need cthreads unit for *nix OSes
  2. The client handler thread, it would work on the given client socket stream
  3. The server, we will create an override constructor to hook when a client connects
  4. Helper routine to get ip:port as string
  5. Overriden constructor for the thread, will call the inherited constructor (with false argument to indicate the thread shouldn't be in suspended state), setting the object to free itself whenever the execution has finished, and assign the socket stream to a private attribute
  6. The core of the thread. Will try to read what the client sends and output it in the server log until the client disconnects
  7. OnConnect handler, prints notification message whenever a client connects and create a handler thread for it
  8. Overriden constructor for the server, assigns the OnConnect handler
  9. Main program. Create event loop object for the server, creates the server, assigning event loop and port to listen, and ready to accept connections...
Phew, go on to the client. This time it's simpler:

{$mode objfpc}{$H+}

uses
  Classes,SysUtils,Sockets,fpAsync,fpSock;

var
  ClientEventLoop: TEventLoop;
begin
  ClientEventLoop := TEventLoop.Create;
  with TTCPClient.Create(nil) do begin
    EventLoop := ClientEventLoop;
    Host := '127.0.0.1';
    Port := 12000;
    Active := true;
    EventLoop.Run;
    Stream.WriteAnsiString('Hello');
    Active := false;
  end;
  ClientEventLoop.Free;
end.

Not numbered since it's only a single main code block. First it creates event loop for the client, create the client, assigning event loop, host and port of the server to connect, activate the connection, send a 'Hello' message to the server and disconnects. Clear enough, eh?

OK, that's all for now. Got any questions? Just ask :)