But first let's understand the difference between static and dynamic web pages:
1. Static web pages:
- static web pages are just plain HTML files which will be manually updated by the developer or website owner whenever he wants;
Here's a drawing of the process that takes place in the case of static web pages

2. Dynamic web pages:
- dynamic web pages are similar to static HTML files, however this HTML files also contain script which is interpreted by a script interpreter which can be almost any script interpreter out there, i.e. perl, php, python, ruby, etc. for this example I've used DWScript;
Here's a drawing of the process that takes place in the case of dynamic web pages

as you can see the noticeable difference between static and dynamic web pages is the script interpreter which comes into play just before serving the HTML to the client.
In this post I won't cover the benefits of using dynamic web pages and the possible exploits.
For this post I've modified the HTTP server which I've created for a video tutorial, so here's the updated source of the uClientContext.pas file:
unit uClientContext;
interface
uses
SysUtils,
Classes,
IdBaseComponent,
IdComponent,
IdCustomTCPServer,
IdCustomHTTPServer,
IdHTTPServer,
IdContext,
dwsComp,
dwsCompiler,
dwsExprs,
dwsClassesLibModule,
dwsMathFunctions,
dwsStringFunctions,
dwsStringResult,
dwsTimeFunctions,
dwsVariantFunctions,
dwsHtmlFilter;
type
TClientContext = class(TIdServerContext)
private
FLogStrings: TStrings;
procedure Log(const s: string);
public
procedure HandleRequest(ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
procedure ServeHTMLFile(const AFileName: string;
ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
public
property LogStrings: TStrings read FLogStrings write FLogStrings;
end;
implementation
var
WebDir: string;
{ TClientContext }
procedure TClientContext.HandleRequest(ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
const
SERROR_404 = 'Error 404 page not found "%s"';
var
LLocation: string;
begin
try
LLocation := ARequestInfo.Document;
if LLocation <> EmptyStr then begin
if (LLocation = '/') or (LLocation = '/*') or SameText(LLocation, '/index.html') then
ServeHTMLFile(WebDir + 'index.html', ARequestInfo, AResponseInfo)
else begin
LLocation := WebDir + Copy(LLocation, 2, MaxInt);
if NOT SameText(ExtractFileExt(LLocation), '.html') then
LLocation := LLocation + '.html';
if FileExists(LLocation) then
ServeHTMLFile(LLocation, ARequestInfo, AResponseInfo)
else
AResponseInfo.ContentText := Format(SERROR_404, [LLocation]);
end;
end else
AResponseInfo.ContentText := Format(SERROR_404, [LLocation]);
except
on E: Exception do
Log('Exception occured from IP ' + Connection.Socket.Binding.PeerIP +
sLineBreak + E.Message);
end; // trye
end;
procedure TClientContext.ServeHTMLFile(const AFileName: string;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
LHTMLFile: TStringList;
LScript: TDelphiWebScript;
LHTMLFilter: TdwsHtmlFilter;
LClasses: TdwsClassesLib;
LProgram: TdwsProgram;
begin
LScript := TDelphiWebScript.Create(NIL);
LScript.Config.ScriptPaths.Add(WebDir);
LClasses := TdwsClassesLib.Create(NIL);
LHTMLFilter := TdwsHtmlFilter.Create(NIL);
LScript.Config.Filter := LHTMLFilter;
LScript.AddUnit(TdwsHtmlUnit.Create(LScript));
LScript.AddUnit(Tdws2StringsUnit.Create(LScript));
LHTMLFile := TStringList.Create;
try
LClasses.Script := LScript;
LHTMLFile.LoadFromFile(AFileName);
LProgram := LScript.Compile(LHTMLFile.Text);
try
if NOT LProgram.Msgs.HasErrors then begin
LProgram.Execute;
AResponseInfo.ContentText := (LProgram.Result as TdwsDefaultResult).Text;
end else
AResponseInfo.ContentText := LProgram.Msgs.AsInfo
finally
FreeAndNil(LProgram);
end; // tryf
finally
FreeAndNil(LHTMLFile);
FreeAndNil(LClasses);
FreeAndNil(LScript);
FreeAndNil(LHTMLFilter);
end; // tryf
end;
procedure TClientContext.Log(const s: string);
begin
if Assigned(FLogStrings) then
FLogStrings.Add(s);
end;
initialization
WebDir := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)) + 'www');
end.
as you can see the source code is pretty similar to the initial code, just that I've added a new method called ServeHTMLFile -- this method is called only if the requested HTML file is found in the www directory.Technique: we don't create the interpreter instance unless the requested file is found in the www directory -- the reason is pretty obvious, we try to avoid memory allocation if it's not necessary, we could also improve the efficiency by caching the files in memory in order to serve them faster(RAM IO is faster than disk IO therefore this will give a significant speed improvement when server has thousands requests per second) however this will be covered in a future post hopefully.
In order to provide a proof of concept I've created a fairly simple "website" which has 3 buttons, each button redirects the client to a new web page:
index.html file
<HTML>
<BODY>
Hello world!!<BR>
<BUTTON ONCLICK="window.location.href='/primes100.html'">show me primes up to 100</BUTTON> <BR>
<BUTTON ONCLICK="window.location.href='/primes200.html'">show me primes up to 200</BUTTON> <BR>
<BUTTON ONCLICK="window.location.href='/primes300.html'">show me primes up to 300</BUTTON> <BR>
</BODY>
</HTML>
very simple, right?we also have a utils.inc file in which we have a method which checks if a number is prime, this file is also located in www directory
function IsPrime(Value: integer): boolean;
var
Index: Integer;
begin
Result := False;
if Value <= 0 then
Exit;
for Index := 2 to Round(Sqrt(Value)) do
if (Value mod Index) = 0 then
Exit;
Result := True;
end;
here are the other 3 HTML files
primes100.html
<HTML>
<BODY>
<%
{$I 'utils.inc'}
var
Index: Integer;
for Index := 1 to 100 do
if IsPrime(Index) then
Send('<BR>' + IntToStr(Index));
%>
</BODY>
</HTML>
primes200.html
<HTML>
<BODY>
<%
{$I 'utils.inc'}
var
Index: Integer;
for Index := 1 to 200 do
if IsPrime(Index) then
Send('<BR>' + IntToStr(Index));
%>
</BODY>
</HTML>
primes300.html
<HTML>
<BODY>
<%
{$I 'utils.inc'}
var
Index: Integer;
for Index := 1 to 300 do
if IsPrime(Index) then
Send('<BR>' + IntToStr(Index));
%>
</BODY>
</HTML>
Now, this is an extremely simple example, but as you can see it can be used as a template for a real hardcore web server.
Unfortunately I don't have enough time these days for more in depth details, but you can download binary + source code or just the source code and enjoy the power and simplicity of DWScript.The application is created in Delphi 2010.
0 comments:
Post a Comment