2016-06-22 17:49:16 +02:00
|
|
|
|
// ***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// Delphi MVC Framework
|
|
|
|
|
//
|
2017-01-05 12:44:34 +01:00
|
|
|
|
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
|
2016-06-22 17:49:16 +02:00
|
|
|
|
//
|
|
|
|
|
// https://github.com/danieleteti/delphimvcframework
|
|
|
|
|
//
|
2017-03-13 20:52:11 +01:00
|
|
|
|
// Collaborators on this file: Ezequiel Juliano M<>ller (ezequieljuliano@gmail.com)
|
|
|
|
|
//
|
2016-06-22 17:49:16 +02:00
|
|
|
|
// ***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
//
|
|
|
|
|
// *************************************************************************** }
|
2015-12-22 12:38:17 +01:00
|
|
|
|
|
2013-10-30 00:48:23 +01:00
|
|
|
|
unit MVCFramework.Router;
|
|
|
|
|
|
2017-03-23 18:51:25 +01:00
|
|
|
|
{$I dmvcframework.inc}
|
|
|
|
|
|
2013-10-30 00:48:23 +01:00
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
uses
|
2017-03-13 20:52:11 +01:00
|
|
|
|
System.Rtti,
|
|
|
|
|
System.SysUtils,
|
|
|
|
|
System.Generics.Collections,
|
|
|
|
|
System.RegularExpressions,
|
|
|
|
|
System.AnsiStrings,
|
2013-10-30 00:48:23 +01:00
|
|
|
|
MVCFramework,
|
2017-03-13 20:52:11 +01:00
|
|
|
|
MVCFramework.Commons,
|
|
|
|
|
IdURI;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
|
|
|
|
type
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
2013-10-30 00:48:23 +01:00
|
|
|
|
TMVCRouter = class
|
|
|
|
|
private
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FRttiContext: TRttiContext;
|
|
|
|
|
FConfig: TMVCConfig;
|
|
|
|
|
FMethodToCall: TRttiMethod;
|
|
|
|
|
FControllerClazz: TMVCControllerClazz;
|
|
|
|
|
FControllerCreateAction: TMVCControllerCreateAction;
|
|
|
|
|
function GetAttribute<T: TCustomAttribute>(const AAttributes: TArray<TCustomAttribute>): T;
|
|
|
|
|
function GetFirstMediaType(const AContentType: string): string;
|
|
|
|
|
|
|
|
|
|
function IsHTTPContentTypeCompatible(
|
|
|
|
|
const ARequestMethodType: TMVCHTTPMethodType;
|
|
|
|
|
var AContentType: string;
|
|
|
|
|
const AAttributes: TArray<TCustomAttribute>): Boolean;
|
|
|
|
|
|
|
|
|
|
function IsHTTPAcceptCompatible(
|
|
|
|
|
const ARequestMethodType: TMVCHTTPMethodType;
|
|
|
|
|
var AAccept: string;
|
|
|
|
|
const AAttributes: TArray<TCustomAttribute>): Boolean;
|
|
|
|
|
|
|
|
|
|
function IsHTTPMethodCompatible(
|
|
|
|
|
const AMethodType: TMVCHTTPMethodType;
|
|
|
|
|
const AAttributes: TArray<TCustomAttribute>): Boolean;
|
|
|
|
|
|
|
|
|
|
function IsCompatiblePath(
|
|
|
|
|
const AMVCPath: string;
|
|
|
|
|
const APath: string;
|
|
|
|
|
var AParams: TMVCRequestParamsTable): Boolean;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
protected
|
2017-03-13 20:52:11 +01:00
|
|
|
|
{ protected declarations }
|
|
|
|
|
public
|
|
|
|
|
class function StringMethodToHTTPMetod(const AValue: string): TMVCHTTPMethodType; static;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
public
|
2017-03-13 20:52:11 +01:00
|
|
|
|
constructor Create(const AConfig: TMVCConfig);
|
|
|
|
|
destructor Destroy; override;
|
|
|
|
|
|
|
|
|
|
function ExecuteRouting(
|
|
|
|
|
const ARequestPathInfo: string;
|
|
|
|
|
const ARequestMethodType: TMVCHTTPMethodType;
|
|
|
|
|
const ARequestContentType: string;
|
|
|
|
|
const ARequestAccept: string;
|
|
|
|
|
const AControllers: TObjectList<TMVCControllerDelegate>;
|
|
|
|
|
const ADefaultContentType: string;
|
|
|
|
|
const ADefaultContentCharset: string;
|
|
|
|
|
var ARequestParams: TMVCRequestParamsTable;
|
|
|
|
|
out AResponseContentType: string;
|
|
|
|
|
out AResponseContentEncoding: string): Boolean;
|
|
|
|
|
|
|
|
|
|
property MethodToCall: TRttiMethod read FMethodToCall;
|
|
|
|
|
property ControllerClazz: TMVCControllerClazz read FControllerClazz;
|
|
|
|
|
property ControllerCreateAction: TMVCControllerCreateAction read FControllerCreateAction;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
{ TMVCRouter }
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
constructor TMVCRouter.Create(const AConfig: TMVCConfig);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
|
|
|
|
inherited Create;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FRttiContext := TRttiContext.Create;
|
|
|
|
|
FConfig := AConfig;
|
|
|
|
|
FMethodToCall := nil;
|
|
|
|
|
FControllerClazz := nil;
|
|
|
|
|
FControllerCreateAction := nil;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
destructor TMVCRouter.Destroy;
|
|
|
|
|
begin
|
|
|
|
|
FRttiContext.Free;
|
|
|
|
|
inherited Destroy;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.ExecuteRouting(const ARequestPathInfo: string;
|
|
|
|
|
const ARequestMethodType: TMVCHTTPMethodType;
|
|
|
|
|
const ARequestContentType, ARequestAccept: string;
|
|
|
|
|
const AControllers: TObjectList<TMVCControllerDelegate>;
|
|
|
|
|
const ADefaultContentType: string;
|
|
|
|
|
const ADefaultContentCharset: string;
|
|
|
|
|
var ARequestParams: TMVCRequestParamsTable;
|
|
|
|
|
out AResponseContentType: string;
|
2014-06-27 15:30:39 +02:00
|
|
|
|
out AResponseContentEncoding: string): Boolean;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LRequestPathInfo: string;
|
|
|
|
|
LRequestAccept: string;
|
|
|
|
|
LRequestContentType: string;
|
|
|
|
|
LControllerMappedPath: string;
|
|
|
|
|
LControllerDelegate: TMVCControllerDelegate;
|
|
|
|
|
LAttributes: TArray<TCustomAttribute>;
|
|
|
|
|
LAtt: TCustomAttribute;
|
|
|
|
|
LRttiType: TRttiType;
|
|
|
|
|
LMethods: TArray<TRTTIMethod>;
|
|
|
|
|
LMethod: TRTTIMethod;
|
|
|
|
|
LFound: Boolean;
|
|
|
|
|
LMethodPath: string;
|
|
|
|
|
LProduceAttribute: MVCProducesAttribute;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
Result := False;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FMethodToCall := nil;
|
|
|
|
|
FControllerClazz := nil;
|
|
|
|
|
FControllerCreateAction := nil;
|
|
|
|
|
|
|
|
|
|
LRequestAccept := ARequestAccept;
|
|
|
|
|
LRequestContentType := ARequestContentType;
|
|
|
|
|
LRequestPathInfo := ARequestPathInfo;
|
|
|
|
|
if (Trim(LRequestPathInfo) = EmptyStr) then
|
|
|
|
|
LRequestPathInfo := '/'
|
2013-10-30 00:48:23 +01:00
|
|
|
|
else
|
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if LRequestPathInfo[1] <> '/' then
|
|
|
|
|
LRequestPathInfo := '/' + LRequestPathInfo;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LRequestPathInfo := TIdURI.PathEncode(LRequestPathInfo);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
2014-02-24 10:20:34 +01:00
|
|
|
|
{ ISAPI CHANGE THE REQUEST PATH INFO START }
|
|
|
|
|
if IsLibrary then
|
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if string(LRequestPathInfo).StartsWith(FConfig.Value[TMVCConfigKey.ISAPIPath]) then
|
|
|
|
|
LRequestPathInfo := LRequestPathInfo.Remove(0, FConfig.Value[TMVCConfigKey.ISAPIPath].Length);
|
|
|
|
|
if Length(LRequestPathInfo) = 0 then
|
|
|
|
|
LRequestPathInfo := '/';
|
2014-02-24 10:20:34 +01:00
|
|
|
|
end;
|
|
|
|
|
{ ISAPI CHANGE THE REQUEST PATH INFO END }
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
TMonitor.Enter(Lock);
|
2014-04-01 00:02:31 +02:00
|
|
|
|
try
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LControllerMappedPath := EmptyStr;
|
|
|
|
|
for LControllerDelegate in AControllers do
|
2014-04-01 00:02:31 +02:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
SetLength(LAttributes, 0);
|
|
|
|
|
LRttiType := FRttiContext.GetType(LControllerDelegate.Clazz.ClassInfo);
|
|
|
|
|
LAttributes := LRttiType.GetAttributes;
|
|
|
|
|
if (LAttributes = nil) then
|
2014-04-01 00:02:31 +02:00
|
|
|
|
Continue;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LFound := False;
|
|
|
|
|
for LAtt in LAttributes do
|
|
|
|
|
if LAtt is MVCPathAttribute then
|
2014-04-01 00:02:31 +02:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LFound := True;
|
|
|
|
|
LControllerMappedPath := MVCPathAttribute(LAtt).Path;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
Break;
|
|
|
|
|
end;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if not LFound then
|
|
|
|
|
raise EMVCException.CreateFmt('Controller %s does not have MVCPath attribute', [LRttiType.Name]);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if (LControllerMappedPath = '/') then
|
|
|
|
|
LControllerMappedPath := '';
|
2013-10-30 00:48:23 +01:00
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if (not LControllerMappedPath.IsEmpty) and (Pos(LControllerMappedPath, LRequestPathInfo) <> 1) then
|
2014-04-01 00:02:31 +02:00
|
|
|
|
Continue;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LMethods := LRttiType.GetMethods;
|
|
|
|
|
for LMethod in LMethods do
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LAttributes := LMethod.GetAttributes;
|
|
|
|
|
for LAtt in LAttributes do
|
|
|
|
|
if LAtt is MVCPathAttribute then
|
|
|
|
|
if IsHTTPMethodCompatible(ARequestMethodType, LAttributes) and
|
|
|
|
|
IsHTTPContentTypeCompatible(ARequestMethodType, LRequestContentType, LAttributes) and
|
|
|
|
|
IsHTTPAcceptCompatible(ARequestMethodType, LRequestAccept, LAttributes) then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
LMethodPath := MVCPathAttribute(LAtt).Path;
|
|
|
|
|
if IsCompatiblePath(LControllerMappedPath + LMethodPath, LRequestPathInfo, ARequestParams) then
|
2013-11-08 23:10:25 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FMethodToCall := LMethod;
|
|
|
|
|
FControllerClazz := LControllerDelegate.Clazz;
|
|
|
|
|
FControllerCreateAction := LControllerDelegate.CreateAction;
|
|
|
|
|
LProduceAttribute := GetAttribute<MVCProducesAttribute>(LAttributes);
|
|
|
|
|
if Assigned(LProduceAttribute) then
|
2014-04-01 00:02:31 +02:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
AResponseContentType := LProduceAttribute.Value;
|
|
|
|
|
AResponseContentEncoding := LProduceAttribute.Encoding;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AResponseContentType := ADefaultContentType;
|
2014-04-10 13:56:23 +02:00
|
|
|
|
AResponseContentEncoding := ADefaultContentCharset;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
end;
|
2014-10-26 20:48:52 +01:00
|
|
|
|
Exit(True);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
finally
|
|
|
|
|
TMonitor.Exit(Lock);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.GetAttribute<T>(const AAttributes: TArray<TCustomAttribute>): T;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
Att: TCustomAttribute;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
|
|
|
|
Result := nil;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
for Att in AAttributes do
|
|
|
|
|
if Att is T then
|
|
|
|
|
Exit(T(Att));
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.GetFirstMediaType(const AContentType: string): string;
|
2014-06-27 15:30:39 +02:00
|
|
|
|
begin
|
|
|
|
|
Result := AContentType;
|
|
|
|
|
while Pos(',', Result) > 0 do
|
|
|
|
|
Result := Copy(Result, 1, Pos(',', Result) - 1);
|
|
|
|
|
while Pos(';', Result) > 0 do
|
2014-10-26 20:48:52 +01:00
|
|
|
|
Result := Copy(Result, 1, Pos(';', Result) - 1);
|
2014-06-27 15:30:39 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.IsCompatiblePath(
|
|
|
|
|
const AMVCPath: string;
|
|
|
|
|
const APath: string;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
var AParams: TMVCRequestParamsTable): Boolean;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
2013-10-30 00:48:23 +01:00
|
|
|
|
function ToPattern(const V: string; Names: TList<string>): string;
|
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
S: string;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
|
|
|
|
Result := V;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
for S in Names do
|
|
|
|
|
Result := StringReplace(Result, '($' + S + ')', '([ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>@\.\_\,%\w\d\x2D\x3A]*)', [rfReplaceAll]);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function GetParametersNames(const V: string): TList<string>;
|
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
S: string;
|
|
|
|
|
Matches: TMatchCollection;
|
|
|
|
|
M: TMatch;
|
|
|
|
|
I: Integer;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
|
|
|
|
Result := TList<string>.Create;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
S := '\(\$([A-Za-z0-9\_]+)\)';
|
|
|
|
|
Matches := TRegEx.Matches(V, S, [roIgnoreCase, roCompiled, roSingleLine]);
|
|
|
|
|
for M in Matches do
|
|
|
|
|
for I := 0 to M.Groups.Count - 1 do
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
S := M.Groups[I].Value;
|
|
|
|
|
if (Length(S) > 0) and (S[1] <> '(') then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
Result.Add(S);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Break;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
RegEx: TRegEx;
|
|
|
|
|
Macth: TMatch;
|
|
|
|
|
Pattern: string;
|
|
|
|
|
I: Integer;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Names: TList<string>;
|
|
|
|
|
begin
|
|
|
|
|
Names := GetParametersNames(AMVCPath);
|
|
|
|
|
try
|
2017-03-13 20:52:11 +01:00
|
|
|
|
Pattern := ToPattern(AMVCPath, Names);
|
|
|
|
|
if (APath = AMVCPath) then
|
2014-10-26 20:48:52 +01:00
|
|
|
|
Exit(True)
|
2013-10-30 00:48:23 +01:00
|
|
|
|
else
|
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
RegEx := TRegEx.Create('^' + Pattern + '$', [roIgnoreCase, roCompiled, roSingleLine]);
|
|
|
|
|
Macth := RegEx.match(APath);
|
|
|
|
|
Result := Macth.Success;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
if Result then
|
2017-03-13 20:52:11 +01:00
|
|
|
|
for I := 1 to pred(Macth.Groups.Count) do
|
|
|
|
|
AParams.Add(Names[I - 1], TIdURI.URLDecode(Macth.Groups[I].Value));
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Names.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.IsHTTPAcceptCompatible(
|
|
|
|
|
const ARequestMethodType: TMVCHTTPMethodType;
|
|
|
|
|
var AAccept: string;
|
|
|
|
|
const AAttributes: TArray<TCustomAttribute>): Boolean;
|
2013-11-09 14:22:11 +01:00
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
I: Integer;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
MethodAccept: string;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FoundOneAttProduces: Boolean;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
2014-06-27 15:30:39 +02:00
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FoundOneAttProduces := False;
|
|
|
|
|
for I := 0 to High(AAttributes) do
|
|
|
|
|
if AAttributes[I] is MVCProducesAttribute then
|
|
|
|
|
begin
|
|
|
|
|
FoundOneAttProduces := True;
|
|
|
|
|
MethodAccept := MVCProducesAttribute(AAttributes[I]).Value;
|
|
|
|
|
AAccept := GetFirstMediaType(AAccept);
|
2014-04-01 00:02:31 +02:00
|
|
|
|
Result := SameText(AAccept, MethodAccept, loInvariantLocale);
|
|
|
|
|
if Result then
|
|
|
|
|
Break;
|
|
|
|
|
end;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
|
|
|
|
Result := (not FoundOneAttProduces) or (FoundOneAttProduces and Result);
|
2014-04-01 00:02:31 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.IsHTTPContentTypeCompatible(
|
|
|
|
|
const ARequestMethodType: TMVCHTTPMethodType;
|
|
|
|
|
var AContentType: string;
|
|
|
|
|
const AAttributes: TArray<TCustomAttribute>): Boolean;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
I: Integer;
|
2014-04-01 00:02:31 +02:00
|
|
|
|
MethodContentType: string;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FoundOneAttConsumes: Boolean;
|
2013-11-09 14:22:11 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if ARequestMethodType in [httpGET, httpDELETE, httpHEAD, httpOPTIONS] then
|
2014-10-26 20:48:52 +01:00
|
|
|
|
Exit(True);
|
2014-03-24 17:37:08 +01:00
|
|
|
|
|
2013-11-09 14:22:11 +01:00
|
|
|
|
Result := False;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
|
|
|
|
FoundOneAttConsumes := False;
|
|
|
|
|
for I := 0 to High(AAttributes) do
|
|
|
|
|
if AAttributes[I] is MVCConsumesAttribute then
|
2013-11-09 14:22:11 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
FoundOneAttConsumes := True;
|
|
|
|
|
MethodContentType := MVCConsumesAttribute(AAttributes[I]).Value;
|
|
|
|
|
AContentType := GetFirstMediaType(AContentType);
|
2014-04-01 00:02:31 +02:00
|
|
|
|
Result := SameText(AContentType, MethodContentType, loInvariantLocale);
|
|
|
|
|
if Result then
|
|
|
|
|
Break;
|
2013-11-09 14:22:11 +01:00
|
|
|
|
end;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
|
|
|
|
Result := (not FoundOneAttConsumes) or (FoundOneAttConsumes and Result);
|
2013-11-09 14:22:11 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
function TMVCRouter.IsHTTPMethodCompatible(
|
|
|
|
|
const AMethodType: TMVCHTTPMethodType;
|
|
|
|
|
const AAttributes: TArray<TCustomAttribute>): Boolean;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
var
|
2017-03-13 20:52:11 +01:00
|
|
|
|
I: Integer;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
MustBeCompatible: Boolean;
|
|
|
|
|
CompatibleMethods: TMVCHTTPMethods;
|
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
2013-10-30 00:48:23 +01:00
|
|
|
|
MustBeCompatible := False;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
for I := 0 to High(AAttributes) do
|
|
|
|
|
if AAttributes[I] is MVCHTTPMethodAttribute then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2014-10-26 20:48:52 +01:00
|
|
|
|
MustBeCompatible := True;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
CompatibleMethods := MVCHTTPMethodAttribute(AAttributes[I]).MVCHTTPMethods;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Result := (AMethodType in CompatibleMethods);
|
|
|
|
|
end;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
|
2013-11-09 14:22:11 +01:00
|
|
|
|
Result := (not MustBeCompatible) or (MustBeCompatible and Result);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2017-03-13 20:52:11 +01:00
|
|
|
|
class function TMVCRouter.StringMethodToHTTPMetod(const AValue: string): TMVCHTTPMethodType;
|
2013-10-30 00:48:23 +01:00
|
|
|
|
begin
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'GET' then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Exit(httpGET);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'POST' then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Exit(httpPOST);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'DELETE' then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Exit(httpDELETE);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'PUT' then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Exit(httpPUT);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'HEAD' then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Exit(httpHEAD);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'OPTIONS' then
|
2013-10-30 00:48:23 +01:00
|
|
|
|
Exit(httpOPTIONS);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'PATCH' then
|
2014-03-24 17:37:08 +01:00
|
|
|
|
Exit(httpPATCH);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
if AValue = 'TRACE' then
|
2014-03-24 17:37:08 +01:00
|
|
|
|
Exit(httpTRACE);
|
2017-03-13 20:52:11 +01:00
|
|
|
|
raise EMVCException.CreateFmt('Unknown HTTP method [%s]', [AValue]);
|
2013-10-30 00:48:23 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end.
|