I have an HTTP Web Broker Server which needs to handle requests such as...
http://myserver.com/versions/2013.6.0.0/ML/Files/SomeFile.exe
The server its self just for reference is hosting information and specific individual files for automatic software updates (where many individual updatable files are involved).
So I create a request handler in the Web Module for this, but the path info of this request (Request.PathInfo
) is...
/versions/2013.6.0.0/ML/Files/SomeFile.exe
...but it needs to detect just the first part...
/versions
Once it detects this, then it needs to handle the following version number...
/2013.6.0.0
...in which case the web server knows the client's requesting data specific to that version. The next part is the application Edition...
/ML
Then I specify that I'm looking for specific files related to this version/edition combo...
/Files
...and finally the actual file...
/SomeFile.exe
This URL does not represent any actual directory on the web server - the actual location of SomeFile.exe
could be entirely different (another story of how it detects where to find those files).
The question is, How should I detect this hierarchy of Path Info and handle it accordingly using the request handler actions (TCollection) available in the Web Module? Because the built-in request handlers assume that there'll only be one level, but this server could have virtually endless levels.
Based off of Rob's comment on the question, I quickly realized how simple this was to accomplish. Using a String List, break down the Path Info into different list items dividing each slash. Then, use whatever custom mechanism to evaluate the first one, then second, and so on. Each variation will trigger a different handler procedure, like so...
unit uUpdateServerWebModule;
interface
uses System.SysUtils, System.Classes, Web.HTTPApp, Update.Common;
type
TWebModule1 = class(TWebModule)
procedure WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
procedure HandleVersionCheck(Request: TWebRequest; Response: TWebResponse;
PathInfo: TStringList);
procedure HandleInfoCheck(Request: TWebRequest; Response: TWebResponse;
PathInfo: TStringList);
procedure HandleException(Request: TWebRequest; Response: TWebResponse;
PathInfo: TStringList; const Code: Integer);
public
{ Public declarations }
end;
var
WebModuleClass: TComponentClass = TWebModule1;
implementation
{$R *.dfm}
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
L: TStringList;
S, T: String;
P: Integer;
procedure A(const Text: String);
begin
S:= S + Text + sLineBreak;
end;
begin
//Break down URL by slashes into list
L:= TStringList.Create;
try
S:= Request.PathInfo;
if Copy(S, Length(S)-1, 1) <> '/' then
S:= S + '/';
Delete(S, 1, 1);
while Length(S) > 0 do begin
P:= Pos('/', S);
T:= Copy(S, 1, P-1);
Delete(S, 1, P);
L.Append(T);
end;
if L.Count > 0 then begin
//Handle path info list
if LowerCase(L[0]) = 'ver' then begin
HandleVersionCheck(Request, Response, L);
end else
if LowerCase(L[0]) = 'info' then begin
HandleInfoCheck(Request, Response, L);
end else begin
HandleException(Request, Response, L, 0);
end;
end else begin
//No page specified, return default page
Response.Content:= 'Application Update Server';
end;
finally
L.Free;
end;
end;
procedure TWebModule1.HandleVersionCheck(Request: TWebRequest;
Response: TWebResponse; PathInfo: TStringList);
var
EC: String;
FN: String;
Ver: TVersion;
begin
if LowerCase(PathInfo[1]) = 'info' then begin
//Next parameter: Edition Code
EC:= LowerCase(PathInfo[2]);
if (EC = 'ml') or (EC = 'sl') or (EC = 'lt') then begin
//Return current version info for specified software edition...
end else begin
HandleException(Request, Response, PathInfo, 4);
end;
end else begin
//Next parameter: Version Number(s)
Ver:= TVersion.Create;
try
Ver.Version:= PathInfo[1];
if (Ver.Ver1 > 0) and (Ver.Ver2 > 0) then begin
//Next parameter: Edition Code
EC:= LowerCase(PathInfo[2]);
if (EC = 'ml') or (EC = 'sl') or (EC = 'lt') then begin
//Next parameter: Version/Edition Commands
if LowerCase(PathInfo[3]) = 'update' then begin
//Return stream of full verion update installer app...
Response.ContentType:= 'application/octet-stream';
end else
if LowerCase(PathInfo[3]) = 'files' then begin
//Next parameter: Specific filename
FN:= PathInfo[4];
//Return stream of specific file...
Response.ContentType:= 'application/octet-stream';
end else begin
HandleException(Request, Response, PathInfo, 1);
end;
end else begin
HandleException(Request, Response, PathInfo, 2);
end;
end else begin
HandleException(Request, Response, PathInfo, 3);
end;
finally
Ver.Free;
end;
end;
end;
procedure TWebModule1.HandleInfoCheck(Request: TWebRequest;
Response: TWebResponse; PathInfo: TStringList);
begin
//Return information about all software and their current versions...
end;
procedure TWebModule1.HandleException(Request: TWebRequest;
Response: TWebResponse; PathInfo: TStringList; const Code: Integer);
begin
//Return error information...
Response.Content:= 'EXCEPTION: '+IntToStr(Code);
end;
end.
That is the full code of the Web Module (main logic)
The primary handling is done from the Default Handler. Essentially all incoming requests are processed through this procedure WebModule1DefaultHandlerAction
which handles each incoming request. From here, it first identifies if there is any path specified at all. If not, it just returns the main landing page. Otherwise, it will first read the first path listed, and call another handler procedure depending on the requested name. In this case, it handles the versions
request and further downloads a particular file (SomeFile.exe
) to be saved in a particular destination.