|
@@ -25,7 +25,7 @@ unit httproute;
|
|
interface
|
|
interface
|
|
|
|
|
|
uses
|
|
uses
|
|
- Classes, SysUtils, httpdefs;
|
|
|
|
|
|
+ Classes, SysUtils, syncobjs, httpdefs;
|
|
|
|
|
|
Type
|
|
Type
|
|
EHTTPRoute = Class(EHTTP);
|
|
EHTTPRoute = Class(EHTTP);
|
|
@@ -192,6 +192,7 @@ Type
|
|
|
|
|
|
THTTPRouter = Class(TComponent)
|
|
THTTPRouter = Class(TComponent)
|
|
private
|
|
private
|
|
|
|
+ FLock : TCriticalSection;
|
|
FAfterRequest: THTTPRouteRequestEvent;
|
|
FAfterRequest: THTTPRouteRequestEvent;
|
|
FBeforeRequest: THTTPRouteRequestEvent;
|
|
FBeforeRequest: THTTPRouteRequestEvent;
|
|
FRouteOptions: TRouteOptions;
|
|
FRouteOptions: TRouteOptions;
|
|
@@ -204,6 +205,9 @@ Type
|
|
FServiceClass : THTTPRouterClass;
|
|
FServiceClass : THTTPRouterClass;
|
|
function GetRouteCount: Integer;
|
|
function GetRouteCount: Integer;
|
|
Protected
|
|
Protected
|
|
|
|
+ // Lock & Unlock list
|
|
|
|
+ Procedure Lock;
|
|
|
|
+ Procedure Unlock;
|
|
// Return an instance of given class with Pattern, Method, IsDefault filled in.
|
|
// Return an instance of given class with Pattern, Method, IsDefault filled in.
|
|
function CreateHTTPRoute(AClass: THTTPRouteClass; const APattern: String; AMethod: TRouteMethod; IsDefault: Boolean ): THTTPRoute; virtual;
|
|
function CreateHTTPRoute(AClass: THTTPRouteClass; const APattern: String; AMethod: TRouteMethod; IsDefault: Boolean ): THTTPRoute; virtual;
|
|
// Override this if you want to use another collection class.
|
|
// Override this if you want to use another collection class.
|
|
@@ -217,6 +221,8 @@ Type
|
|
Public
|
|
Public
|
|
Constructor Create(AOwner: TComponent); override;
|
|
Constructor Create(AOwner: TComponent); override;
|
|
Destructor Destroy; override;
|
|
Destructor Destroy; override;
|
|
|
|
+ // Find default route for this method.
|
|
|
|
+ function FindDefaultRoute(AMethod: TRouteMethod): THTTPRoute;
|
|
// Delete given route by index.
|
|
// Delete given route by index.
|
|
Procedure DeleteRoute(AIndex : Integer);
|
|
Procedure DeleteRoute(AIndex : Integer);
|
|
// Delete given route by index.
|
|
// Delete given route by index.
|
|
@@ -257,6 +263,10 @@ Type
|
|
function GetHTTPRoute(const Path: String; AMethod: TRouteMethod; Params: TStrings): THTTPRoute;
|
|
function GetHTTPRoute(const Path: String; AMethod: TRouteMethod; Params: TStrings): THTTPRoute;
|
|
// Do actual routing. Exceptions raised will not be caught. Request must be initialized
|
|
// Do actual routing. Exceptions raised will not be caught. Request must be initialized
|
|
Procedure RouteRequest(ARequest : TRequest; AResponse : TResponse);
|
|
Procedure RouteRequest(ARequest : TRequest; AResponse : TResponse);
|
|
|
|
+ // Move route with aRouteID before default route with same method.
|
|
|
|
+ Function MoveRouteBeforeDefault(aRouteID : Integer) : Boolean;
|
|
|
|
+ // Move route with aRouteID before default route.
|
|
|
|
+ Function MoveRouteBefore(aRoute1,aRoute2 : THTTPRoute) : Boolean;
|
|
// Indexed access to the registered routes.
|
|
// Indexed access to the registered routes.
|
|
Property Routes [AIndex : Integer] : THTTPRoute Read GetR; Default;
|
|
Property Routes [AIndex : Integer] : THTTPRoute Read GetR; Default;
|
|
// Number of registered routes.
|
|
// Number of registered routes.
|
|
@@ -399,7 +409,12 @@ end;
|
|
|
|
|
|
function THTTPRouter.GetR(AIndex : Integer): THTTPRoute;
|
|
function THTTPRouter.GetR(AIndex : Integer): THTTPRoute;
|
|
begin
|
|
begin
|
|
- Result:=FRoutes[AIndex]
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ Result:=FRoutes[AIndex]
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
class procedure THTTPRouter.DoneService;
|
|
class procedure THTTPRouter.DoneService;
|
|
@@ -409,7 +424,22 @@ end;
|
|
|
|
|
|
function THTTPRouter.GetRouteCount: Integer;
|
|
function THTTPRouter.GetRouteCount: Integer;
|
|
begin
|
|
begin
|
|
- Result:=FRoutes.Count;
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ Result:=FRoutes.Count;
|
|
|
|
+ finally
|
|
|
|
+ UnLock;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure THTTPRouter.Lock;
|
|
|
|
+begin
|
|
|
|
+ FLock.Enter;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure THTTPRouter.Unlock;
|
|
|
|
+begin
|
|
|
|
+ FLock.Leave;
|
|
end;
|
|
end;
|
|
|
|
|
|
function THTTPRouter.CreateRouteList: THTTPRouteList;
|
|
function THTTPRouter.CreateRouteList: THTTPRouteList;
|
|
@@ -430,14 +460,19 @@ Var
|
|
|
|
|
|
begin
|
|
begin
|
|
DI:=-1;
|
|
DI:=-1;
|
|
- For I:=0 to FRoutes.Count-1 do
|
|
|
|
- begin
|
|
|
|
- R:=FRoutes[I];
|
|
|
|
- if R.Default then
|
|
|
|
- DI:=I;
|
|
|
|
- if R.Matches(APattern,AMethod,FRouteOptions) then
|
|
|
|
- Raise EHTTPRoute.CreateFmt(EDuplicateRoute,[APattern,RouteMethodToString(AMethod)]);
|
|
|
|
- end;
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ For I:=0 to FRoutes.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ R:=FRoutes[I];
|
|
|
|
+ if R.Default then
|
|
|
|
+ DI:=I;
|
|
|
|
+ if R.Matches(APattern,AMethod,FRouteOptions) then
|
|
|
|
+ Raise EHTTPRoute.CreateFmt(EDuplicateRoute,[APattern,RouteMethodToString(AMethod)]);
|
|
|
|
+ end;
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
if isDefault and (DI<>-1) then
|
|
if isDefault and (DI<>-1) then
|
|
Raise EHTTPRoute.CreateFmt(EDuplicateDefaultRoute,[APattern,RouteMethodToString(AMethod)]);
|
|
Raise EHTTPRoute.CreateFmt(EDuplicateDefaultRoute,[APattern,RouteMethodToString(AMethod)]);
|
|
end;
|
|
end;
|
|
@@ -480,27 +515,44 @@ begin
|
|
inherited Create(AOwner);
|
|
inherited Create(AOwner);
|
|
froutes:=CreateRouteList;
|
|
froutes:=CreateRouteList;
|
|
FIntercepts:=CreateInterceptorList;
|
|
FIntercepts:=CreateInterceptorList;
|
|
|
|
+ FLock:=TCriticalSection.Create;
|
|
end;
|
|
end;
|
|
|
|
|
|
destructor THTTPRouter.Destroy;
|
|
destructor THTTPRouter.Destroy;
|
|
begin
|
|
begin
|
|
|
|
+ FreeAndNil(FLock);
|
|
FreeAndNil(FRoutes);
|
|
FreeAndNil(FRoutes);
|
|
inherited Destroy;
|
|
inherited Destroy;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THTTPRouter.DeleteRoute(AIndex: Integer);
|
|
procedure THTTPRouter.DeleteRoute(AIndex: Integer);
|
|
begin
|
|
begin
|
|
- FRoutes.Delete(Aindex)
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ FRoutes.Delete(Aindex)
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THTTPRouter.DeleteRouteByID(AID: Integer);
|
|
procedure THTTPRouter.DeleteRouteByID(AID: Integer);
|
|
begin
|
|
begin
|
|
- FRoutes.FindItemID(AID).Free;
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ FRoutes.FindItemID(AID).Free;
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure THTTPRouter.DeleteRoute(ARoute: THTTPRoute);
|
|
procedure THTTPRouter.DeleteRoute(ARoute: THTTPRoute);
|
|
begin
|
|
begin
|
|
- ARoute.Free;
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ ARoute.Free;
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
class function THTTPRouter.Service: THTTPRouter;
|
|
class function THTTPRouter.Service: THTTPRouter;
|
|
@@ -544,7 +596,12 @@ Var
|
|
Intr : TRequestInterceptorItem;
|
|
Intr : TRequestInterceptorItem;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Intr:=FIntercepts.AddInterceptor(aName);
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ Intr:=FIntercepts.AddInterceptor(aName);
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
Intr.Event:=aEvent;
|
|
Intr.Event:=aEvent;
|
|
Intr.InterceptAt:=aAt;
|
|
Intr.InterceptAt:=aAt;
|
|
end;
|
|
end;
|
|
@@ -552,7 +609,12 @@ end;
|
|
procedure THTTPRouter.UnRegisterInterceptor(const aName: String);
|
|
procedure THTTPRouter.UnRegisterInterceptor(const aName: String);
|
|
|
|
|
|
begin
|
|
begin
|
|
- FIntercepts.FindInterceptor(aName).Free;
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ FIntercepts.FindInterceptor(aName).Free;
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function THTTPRouter.RegisterRoute(const APattern: String;AData : Pointer;
|
|
function THTTPRouter.RegisterRoute(const APattern: String;AData : Pointer;
|
|
@@ -608,7 +670,12 @@ function THTTPRouter.CreateHTTPRoute(AClass : THTTPRouteClass; const APattern: S
|
|
|
|
|
|
begin
|
|
begin
|
|
CheckDuplicate(APattern,AMethod,isDefault);
|
|
CheckDuplicate(APattern,AMethod,isDefault);
|
|
- Result:=AClass.Create(FRoutes);
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ Result:=AClass.Create(FRoutes);
|
|
|
|
+ finally
|
|
|
|
+ UnLock;
|
|
|
|
+ end;
|
|
With Result do
|
|
With Result do
|
|
begin
|
|
begin
|
|
URLPattern:=APattern;
|
|
URLPattern:=APattern;
|
|
@@ -658,23 +725,39 @@ begin
|
|
MethodMisMatch:=False;
|
|
MethodMisMatch:=False;
|
|
Result:=Nil;
|
|
Result:=Nil;
|
|
I:=0;
|
|
I:=0;
|
|
- While (Result=Nil) and (I<FRoutes.Count) do
|
|
|
|
- begin
|
|
|
|
- Result:=FRoutes[i];
|
|
|
|
- If Not Result.MatchPattern(APathInfo,Params,FRouteOptions) then
|
|
|
|
- Result:=Nil
|
|
|
|
- else if Not Result.MatchMethod(AMethod) then
|
|
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ While (Result=Nil) and (I<FRoutes.Count) do
|
|
begin
|
|
begin
|
|
- Result:=Nil;
|
|
|
|
- Params.Clear;
|
|
|
|
- MethodMisMatch:=True;
|
|
|
|
|
|
+ Result:=FRoutes[i];
|
|
|
|
+ If Not Result.MatchPattern(APathInfo,Params,FRouteOptions) then
|
|
|
|
+ Result:=Nil
|
|
|
|
+ else if Not Result.MatchMethod(AMethod) then
|
|
|
|
+ begin
|
|
|
|
+ Result:=Nil;
|
|
|
|
+ Params.Clear;
|
|
|
|
+ MethodMisMatch:=True;
|
|
|
|
+ end;
|
|
|
|
+ Inc(I);
|
|
end;
|
|
end;
|
|
- Inc(I);
|
|
|
|
- end;
|
|
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
// Find default route.
|
|
// Find default route.
|
|
if (Result=Nil) then
|
|
if (Result=Nil) then
|
|
- begin
|
|
|
|
- I:=0;
|
|
|
|
|
|
+ Result:=FindDefaultRoute(aMethod);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function THTTPRouter.FindDefaultRoute(AMethod: TRouteMethod) : THTTPRoute;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ i : Integer;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ I:=0;
|
|
|
|
+ Result:=nil;
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
While (Result=Nil) and (I<FRoutes.Count) do
|
|
While (Result=Nil) and (I<FRoutes.Count) do
|
|
begin
|
|
begin
|
|
Result:=FRoutes[i];
|
|
Result:=FRoutes[i];
|
|
@@ -682,7 +765,9 @@ begin
|
|
Result:=Nil;
|
|
Result:=Nil;
|
|
Inc(I);
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
- end;
|
|
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function THTTPRouter.GetHTTPRoute(const Path: String; AMethod: TRouteMethod; Params : TStrings): THTTPRoute;
|
|
function THTTPRouter.GetHTTPRoute(const Path: String; AMethod: TRouteMethod; Params : TStrings): THTTPRoute;
|
|
@@ -719,6 +804,37 @@ begin
|
|
FAfterRequest(Self,ARequest,AResponse);
|
|
FAfterRequest(Self,ARequest,AResponse);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function THTTPRouter.MoveRouteBeforeDefault(aRouteID : integer): Boolean;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ aRoute,aDefaultRoute : THTTPRoute;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Result:=False;
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ aRoute:=THTTPRoute(FRoutes.FindItemID(aRouteID));
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
|
|
+ aDefaultRoute:=FindDefaultRoute(aRoute.Method);
|
|
|
|
+ Result:=MoveRouteBefore(aRoute,aDefaultRoute);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function THTTPRouter.MoveRouteBefore(aRoute1, aRoute2: THTTPRoute): Boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:=Assigned(aRoute1) and Assigned(aRoute2) and (aRoute1.Index>aRoute2.Index);
|
|
|
|
+ if Result then
|
|
|
|
+ begin
|
|
|
|
+ Lock;
|
|
|
|
+ try
|
|
|
|
+ FRoutes.Move(aRoute1.Index,aRoute2.Index);
|
|
|
|
+ finally
|
|
|
|
+ Unlock;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
{ THTTPRouteInterface }
|
|
{ THTTPRouteInterface }
|
|
|
|
|
|
procedure THTTPRouteInterface.DoHandleRequest(ARequest: TRequest;
|
|
procedure THTTPRouteInterface.DoHandleRequest(ARequest: TRequest;
|
|
@@ -945,7 +1061,7 @@ end;
|
|
|
|
|
|
function THTTPRoute.MatchMethod(const AMethod: TRouteMethod): Boolean;
|
|
function THTTPRoute.MatchMethod(const AMethod: TRouteMethod): Boolean;
|
|
begin
|
|
begin
|
|
- Result:=(Method=rmAll) or (Method=AMethod);
|
|
|
|
|
|
+ Result:=(Method=rmAll) or (Method=AMethod) or (aMethod=rmAll);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ THTTPRouteCallbackex }
|
|
{ THTTPRouteCallbackex }
|