mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-13 21:49:11 +02:00
* Introduce route options to select case sensitivity or not. (default not case sensitive)
git-svn-id: trunk@38956 -
This commit is contained in:
parent
c2181a302d
commit
9d2e5308fb
@ -37,6 +37,8 @@ Type
|
|||||||
// Some common HTTP methods.
|
// Some common HTTP methods.
|
||||||
|
|
||||||
TRouteMethod = (rmUnknown,rmAll,rmGet,rmPost,rmPut,rmDelete,rmOptions,rmHead, rmTrace);
|
TRouteMethod = (rmUnknown,rmAll,rmGet,rmPost,rmPut,rmDelete,rmOptions,rmHead, rmTrace);
|
||||||
|
TRouteOption = (roCaseSensitive,roEmptyMatchesAll);
|
||||||
|
TRouteOptions = Set of TRouteOption;
|
||||||
|
|
||||||
{ THTTPRoute }
|
{ THTTPRoute }
|
||||||
|
|
||||||
@ -51,11 +53,13 @@ Type
|
|||||||
Public
|
Public
|
||||||
Destructor Destroy; override;
|
Destructor Destroy; override;
|
||||||
Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse);
|
Procedure HandleRequest(ARequest : TRequest; AResponse : TResponse);
|
||||||
Function Matches(Const APattern : String; AMethod : TRouteMethod) : Boolean;
|
Function Matches(Const APattern : String; AMethod : TRouteMethod; Options : TRouteOptions) : Boolean;
|
||||||
Function MatchPattern(Const Path : String; L : TStrings) : Boolean;
|
Function MatchPattern(Const Path : String; L : TStrings; Options : TRouteOptions) : Boolean;
|
||||||
Function MatchMethod(Const AMethod : TRouteMethod) : Boolean;
|
Function MatchMethod(Const AMethod : TRouteMethod) : Boolean;
|
||||||
Published
|
Published
|
||||||
|
// Default route is per method. This means you can register
|
||||||
Property Default : Boolean Read FDefault Write FDefault;
|
Property Default : Boolean Read FDefault Write FDefault;
|
||||||
|
// Depending on options, an empty URLPattern matches all, and acts as default.
|
||||||
Property URLPattern : String Read FURLPattern Write SetURLPattern;
|
Property URLPattern : String Read FURLPattern Write SetURLPattern;
|
||||||
Property Method : TRouteMethod Read FMethod Write FMethod;
|
Property Method : TRouteMethod Read FMethod Write FMethod;
|
||||||
end;
|
end;
|
||||||
@ -154,6 +158,7 @@ Type
|
|||||||
private
|
private
|
||||||
FAfterRequest: THTTPRouteRequestEvent;
|
FAfterRequest: THTTPRouteRequestEvent;
|
||||||
FBeforeRequest: THTTPRouteRequestEvent;
|
FBeforeRequest: THTTPRouteRequestEvent;
|
||||||
|
FRouteOptions: TRouteOptions;
|
||||||
FRoutes : THTTPRouteList;
|
FRoutes : THTTPRouteList;
|
||||||
function GetR(AIndex : Integer): THTTPRoute;
|
function GetR(AIndex : Integer): THTTPRoute;
|
||||||
Class Procedure DoneService;
|
Class Procedure DoneService;
|
||||||
@ -219,6 +224,8 @@ Type
|
|||||||
Property BeforeRequest : THTTPRouteRequestEvent Read FBeforeRequest Write FBeforeRequest;
|
Property BeforeRequest : THTTPRouteRequestEvent Read FBeforeRequest Write FBeforeRequest;
|
||||||
// Called after the request is routed, if no exception was raised during or before the request.
|
// Called after the request is routed, if no exception was raised during or before the request.
|
||||||
Property AfterRequest : THTTPRouteRequestEvent Read FAfterRequest Write FAfterRequest;
|
Property AfterRequest : THTTPRouteRequestEvent Read FAfterRequest Write FAfterRequest;
|
||||||
|
// Global options used when routing a request.
|
||||||
|
Property RouteOptions : TRouteOptions Read FRouteOptions Write FRouteOptions;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function RouteMethodToString (R : TRouteMethod) : String;
|
Function RouteMethodToString (R : TRouteMethod) : String;
|
||||||
@ -318,7 +325,7 @@ begin
|
|||||||
R:=FRoutes[I];
|
R:=FRoutes[I];
|
||||||
if R.Default then
|
if R.Default then
|
||||||
DI:=I;
|
DI:=I;
|
||||||
if R.Matches(APattern,AMethod) then
|
if R.Matches(APattern,AMethod,FRouteOptions) then
|
||||||
Raise EHTTPRoute.CreateFmt(EDuplicateRoute,[APattern,RouteMethodToString(AMethod)]);
|
Raise EHTTPRoute.CreateFmt(EDuplicateRoute,[APattern,RouteMethodToString(AMethod)]);
|
||||||
end;
|
end;
|
||||||
if isDefault and (DI<>-1) then
|
if isDefault and (DI<>-1) then
|
||||||
@ -526,7 +533,7 @@ begin
|
|||||||
While (Result=Nil) and (I<FRoutes.Count) do
|
While (Result=Nil) and (I<FRoutes.Count) do
|
||||||
begin
|
begin
|
||||||
Result:=FRoutes[i];
|
Result:=FRoutes[i];
|
||||||
If Not Result.MatchPattern(APathInfo,Params) then
|
If Not Result.MatchPattern(APathInfo,Params,FRouteOptions) then
|
||||||
Result:=Nil
|
Result:=Nil
|
||||||
else if Not Result.MatchMethod(AMethod) then
|
else if Not Result.MatchMethod(AMethod) then
|
||||||
begin
|
begin
|
||||||
@ -536,6 +543,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
Inc(I);
|
Inc(I);
|
||||||
end;
|
end;
|
||||||
|
// Find default route.
|
||||||
|
if (Result=Nil) then
|
||||||
|
begin
|
||||||
|
I:=0;
|
||||||
|
While (Result=Nil) and (I<FRoutes.Count) do
|
||||||
|
begin
|
||||||
|
Result:=FRoutes[i];
|
||||||
|
if Not (Result.Default and Result.MatchMethod(AMethod)) then
|
||||||
|
Result:=Nil;
|
||||||
|
Inc(I);
|
||||||
|
end;
|
||||||
|
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;
|
||||||
@ -605,7 +624,7 @@ Var
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
V:=IncludeHTTPPathDelimiter(AValue);
|
V:=IncludeHTTPPathDelimiter(AValue);
|
||||||
if (V<>'/') and (V[1]='/') then
|
if (V<>'') and (V<>'/') and (V[1]='/') then
|
||||||
Delete(V,1,1);
|
Delete(V,1,1);
|
||||||
if FURLPattern=V then Exit;
|
if FURLPattern=V then Exit;
|
||||||
FURLPattern:=V;
|
FURLPattern:=V;
|
||||||
@ -627,22 +646,24 @@ begin
|
|||||||
DoHandleRequest(ARequest,AResponse);
|
DoHandleRequest(ARequest,AResponse);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function THTTPRoute.Matches(const APattern: String; AMethod: TRouteMethod
|
function THTTPRoute.Matches(const APattern: String; AMethod: TRouteMethod; Options: TRouteOptions): Boolean;
|
||||||
): Boolean;
|
|
||||||
begin
|
begin
|
||||||
Result:=(CompareText(URLPattern,APattern)=0)
|
Result:=((Method=rmAll) or (AMethod=Method));
|
||||||
and ((Method=rmAll) or (AMethod=Method))
|
if Result then
|
||||||
|
Result:=SameText(URLPattern,APattern) or ((URLPattern='') and (roEmptyMatchesAll in Options))
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function THTTPRoute.MatchPattern(Const Path : String; L : TStrings) : Boolean;
|
Function THTTPRoute.MatchPattern(Const Path : String; L : TStrings; Options: TRouteOptions) : Boolean;
|
||||||
|
|
||||||
|
// This is used only with special chars, so we do not check case sensitivity
|
||||||
Function StartsWith(C : Char; S : String): Boolean;
|
Function StartsWith(C : Char; S : String): Boolean;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=(Length(S)>0) and (S[1]=C);
|
Result:=(Length(S)>0) and (S[1]=C);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Function EndsWith(C : Char; S : String): Boolean;
|
// This is used only with special chars, so we do not check case sensitivity
|
||||||
|
Function EndsWith(C : Char; S : String): Boolean;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
L : Integer;
|
L : Integer;
|
||||||
@ -651,6 +672,15 @@ Function THTTPRoute.MatchPattern(Const Path : String; L : TStrings) : Boolean;
|
|||||||
L:=Length(S);
|
L:=Length(S);
|
||||||
Result:=(L>0) and (S[L]=C);
|
Result:=(L>0) and (S[L]=C);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Function SameString(A,B : String) : Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if roCaseSensitive in Options then
|
||||||
|
Result:=(A=B)
|
||||||
|
else
|
||||||
|
Result:=SameText(A,B);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure ExtractNextPathLevel(var ALeft: string;
|
procedure ExtractNextPathLevel(var ALeft: string;
|
||||||
@ -700,9 +730,9 @@ var
|
|||||||
VLeftPat, VRightPat, VLeftVal, VRightVal, VVal, VPat, VName: string;
|
VLeftPat, VRightPat, VLeftVal, VRightVal, VVal, VPat, VName: string;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:= False;
|
Result:=False;
|
||||||
if (URLPattern='') then
|
if (URLPattern='') then
|
||||||
Exit; // Maybe empty pattern should match any path?
|
Exit(roEmptyMatchesAll in Options);
|
||||||
APathInfo:=Path;
|
APathInfo:=Path;
|
||||||
APattern:=URLPattern;
|
APattern:=URLPattern;
|
||||||
Delete(APattern, Pos('?', APattern), MaxInt);
|
Delete(APattern, Pos('?', APattern), MaxInt);
|
||||||
@ -750,7 +780,7 @@ begin
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
// *path/const
|
// *path/const
|
||||||
if not ((VPat='') and (VLeftPat='')) and Not SameText(VPat,VVal) then
|
if not ((VPat='') and (VLeftPat='')) and Not SameString(VPat,VVal) then
|
||||||
Exit;
|
Exit;
|
||||||
// Check if we already done
|
// Check if we already done
|
||||||
if (VLeftPat='') or (VLeftVal='') then
|
if (VLeftPat='') or (VLeftVal='') then
|
||||||
@ -767,7 +797,7 @@ begin
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
// const
|
// const
|
||||||
if Not SameText(VPat,VVal) then
|
if Not SameString(VPat,VVal) then
|
||||||
Exit;
|
Exit;
|
||||||
// Check if we already done
|
// Check if we already done
|
||||||
if (VRightPat='') or (VRightVal='') then
|
if (VRightPat='') or (VRightVal='') then
|
||||||
|
Loading…
Reference in New Issue
Block a user