mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 15:55:54 +01:00
This commit is contained in:
parent
1b9abb39d6
commit
ec799cf573
@ -59,17 +59,24 @@ begin
|
||||
Config[TMVCConfigKey.ExposeServerSignature] := 'true';
|
||||
// Max request size in bytes
|
||||
Config[TMVCConfigKey.MaxRequestSize] := IntToStr(TMVCConstants.DEFAULT_MAX_REQUEST_SIZE);
|
||||
Config[TMVCConfigKey.LoadSystemControllers] := 'false';
|
||||
end);
|
||||
FMVC
|
||||
.AddController(TMyController);
|
||||
|
||||
|
||||
{ // Allows all origins -> * }
|
||||
//FMVC.AddMiddleware(TMVCCORSMiddleware.Create);
|
||||
|
||||
{ **************************************************************************** }
|
||||
{ Enable one of the following lines to configure CORS support in different way }
|
||||
{ **************************************************************************** }
|
||||
|
||||
{ // Allows all origins -> * }
|
||||
FMVC.AddMiddleware(TMVCCORSMiddleware.Create('https://anotherserver.com,http://localhost:9090'));
|
||||
FMVC.AddMiddleware(TMVCCORSMiddleware.Create);
|
||||
|
||||
{ // Allows 2 origins }
|
||||
// FMVC.AddMiddleware(TMVCCORSMiddleware.Create('https://anotherserver.com,http://localhost:9090'));
|
||||
|
||||
{ // Disallow localhost:9090 }
|
||||
// FMVC.AddMiddleware(TMVCCORSMiddleware.Create('https://anotherserver.com'));
|
||||
end;
|
||||
|
||||
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
|
||||
|
@ -9,20 +9,37 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<button id="btn">Click Here!</button>
|
||||
<h1>DMVCFramework CORS Support Sample</h1>
|
||||
<h3>This page must be served by "SimpleWebServer.exe" project, otherwise the demo doesn't work correctly.</h3>
|
||||
<p>Change CORS configuration in "middleware_cors\WebModuleU.pas" (there are commented lines)</p>
|
||||
<button id="btnCORS">POST request with CORS enabled!</button>
|
||||
<button id="btnNoCORS">POST request with No-CORS!</button>
|
||||
<div id="output"></div>
|
||||
|
||||
<script defer>
|
||||
let output = document.getElementById('output');
|
||||
document.getElementById('btn').onclick = () => {
|
||||
|
||||
document.getElementById('btnNoCORS').onclick = () => {
|
||||
fetch('http://localhost:8080/api/customers', {
|
||||
"mode":"no-cors",
|
||||
"method": 'POST',
|
||||
"body": JSON.stringify({ "hello": "world" })
|
||||
})
|
||||
.then((res) => {
|
||||
output.innerHTML = "Request done but response is opaque to javascript";
|
||||
});
|
||||
};
|
||||
|
||||
document.getElementById('btnCORS').onclick = () => {
|
||||
fetch('http://localhost:8080/api/customers', {
|
||||
"method": 'POST',
|
||||
"body": JSON.stringify({ "hello": "world" })
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((json) => {
|
||||
output.innerHTML = json['data']["message"]
|
||||
output.innerHTML = JSON.stringify(json);
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
@ -58,6 +58,11 @@ type
|
||||
/// Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
||||
/// </summary>
|
||||
ALLOWS_METHODS = 'POST,GET,OPTIONS,PUT,DELETE';
|
||||
/// <summary>
|
||||
/// Indicates the number of seconds (60 by default) the information provided by
|
||||
/// the `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers` headers can be cached.
|
||||
/// </summary>
|
||||
ACCESS_CONTROL_MAX_AGE = 60;
|
||||
end;
|
||||
|
||||
TMVCCORSMiddleware = class(TInterfacedObject, IMVCMiddleware)
|
||||
@ -68,8 +73,12 @@ type
|
||||
FAllowsMethods: string;
|
||||
FExposeHeaders: string;
|
||||
FAllowsHeaders: string;
|
||||
FAccessControlMaxAge: string;
|
||||
protected
|
||||
function GetAllowedOriginURL(AContext: TWebContext): String; virtual;
|
||||
procedure FillCommonHeaders(AContext: TWebContext; const AAllowOrigin: String); virtual;
|
||||
procedure HandlePreflightRequest(AContext: TWebContext; var AHandled: Boolean); virtual;
|
||||
procedure HandleRequest(AContext: TWebContext; var AHandled: Boolean); virtual;
|
||||
|
||||
procedure OnBeforeRouting(
|
||||
AContext: TWebContext;
|
||||
@ -99,7 +108,8 @@ type
|
||||
const AAllowsCredentials: Boolean = TMVCCORSDefaults.ALLOWS_CREDENTIALS;
|
||||
const AExposeHeaders: String = TMVCCORSDefaults.EXPOSE_HEADERS;
|
||||
const AAllowsHeaders: String = TMVCCORSDefaults.ALLOWS_HEADERS;
|
||||
const AAllowsMethods: string = TMVCCORSDefaults.ALLOWS_METHODS
|
||||
const AAllowsMethods: string = TMVCCORSDefaults.ALLOWS_METHODS;
|
||||
const AAccessControlMaxAge: Integer = TMVCCORSDefaults.ACCESS_CONTROL_MAX_AGE
|
||||
); virtual;
|
||||
end;
|
||||
|
||||
@ -108,7 +118,7 @@ type
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils;
|
||||
System.SysUtils, System.Classes;
|
||||
|
||||
{ TMVCCORSMiddleware }
|
||||
|
||||
@ -117,14 +127,28 @@ constructor TMVCCORSMiddleware.Create(
|
||||
const AAllowsCredentials: Boolean;
|
||||
const AExposeHeaders: String;
|
||||
const AAllowsHeaders: String;
|
||||
const AAllowsMethods: string
|
||||
const AAllowsMethods: string;
|
||||
const AAccessControlMaxAge: Integer
|
||||
);
|
||||
begin
|
||||
inherited Create;
|
||||
FAllowedOriginURLs := AAllowedOriginURLs.Split([',']);
|
||||
FAllowsCredentials := AAllowsCredentials;
|
||||
FExposeHeaders := AExposeHeaders;
|
||||
FAllowsHeaders := AAllowsHeaders;
|
||||
FAllowsMethods := AAllowsMethods;
|
||||
FAccessControlMaxAge := IntToStr(AAccessControlMaxAge);
|
||||
end;
|
||||
|
||||
procedure TMVCCORSMiddleware.FillCommonHeaders(AContext: TWebContext; const AAllowOrigin: String);
|
||||
var
|
||||
lCustomHeaders: TStrings;
|
||||
begin
|
||||
lCustomHeaders := AContext.Response.RawWebResponse.CustomHeaders;
|
||||
lCustomHeaders.Values['Access-Control-Allow-Origin'] := AAllowOrigin;
|
||||
lCustomHeaders.Values['Access-Control-Allow-Methods'] := FAllowsMethods;
|
||||
lCustomHeaders.Values['Access-Control-Allow-Headers'] := FAllowsHeaders;
|
||||
lCustomHeaders.Values['Access-Control-Max-Age'] := FAccessControlMaxAge;
|
||||
end;
|
||||
|
||||
function TMVCCORSMiddleware.GetAllowedOriginURL(AContext: TWebContext): String;
|
||||
@ -147,6 +171,44 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCCORSMiddleware.HandlePreflightRequest(AContext: TWebContext;
|
||||
var AHandled: Boolean);
|
||||
var
|
||||
lAllowOrigin: String;
|
||||
begin
|
||||
// https://fetch.spec.whatwg.org/#cors-preflight-request
|
||||
lAllowOrigin := GetAllowedOriginURL(AContext);
|
||||
AContext.Response.StatusCode := HTTP_STATUS.NoContent;
|
||||
if not lAllowOrigin.IsEmpty then
|
||||
begin
|
||||
FillCommonHeaders(AContext, lAllowOrigin);
|
||||
end;
|
||||
AHandled := True;
|
||||
end;
|
||||
|
||||
procedure TMVCCORSMiddleware.HandleRequest(AContext: TWebContext;
|
||||
var AHandled: Boolean);
|
||||
var
|
||||
lAllowOrigin: String;
|
||||
lCustomHeaders: TStrings;
|
||||
begin
|
||||
// https://fetch.spec.whatwg.org/#http-responses
|
||||
lAllowOrigin := GetAllowedOriginURL(AContext);
|
||||
if not lAllowOrigin.IsEmpty then
|
||||
begin
|
||||
FillCommonHeaders(AContext, lAllowOrigin);
|
||||
lCustomHeaders := AContext.Response.RawWebResponse.CustomHeaders;
|
||||
lCustomHeaders.Values['Access-Control-Expose-Headers'] := FExposeHeaders; {only for not preflight requests}
|
||||
if FAllowsCredentials then
|
||||
begin
|
||||
// Omit Access-Control-Allow-Credentials if <> true
|
||||
// https://github.com/danieleteti/delphimvcframework/issues/679#issuecomment-1676535853
|
||||
lCustomHeaders.Values['Access-Control-Allow-Credentials'] := 'true';
|
||||
end;
|
||||
end;
|
||||
AHandled := False;
|
||||
end;
|
||||
|
||||
procedure TMVCCORSMiddleware.OnAfterControllerAction(
|
||||
AContext: TWebContext;
|
||||
const AControllerQualifiedClassName: string; const AActionName: string;
|
||||
@ -168,24 +230,18 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMVCCORSMiddleware.OnBeforeRouting(AContext: TWebContext; var AHandled: Boolean);
|
||||
var
|
||||
lAllowOrigin: String;
|
||||
begin
|
||||
AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Origin'] := GetAllowedOriginURL(AContext);
|
||||
AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Methods'] := FAllowsMethods;
|
||||
AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Headers'] := FAllowsHeaders;
|
||||
|
||||
if FAllowsCredentials then
|
||||
if AContext.Request.HTTPMethod <> httpOPTIONS then
|
||||
begin
|
||||
// Omit Access-Control-Allow-Credentials if <> true
|
||||
// https://github.com/danieleteti/delphimvcframework/issues/679#issuecomment-1676535853
|
||||
AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Allow-Credentials'] := 'true';
|
||||
end;
|
||||
AContext.Response.RawWebResponse.CustomHeaders.Values['Access-Control-Expose-Headers'] := FExposeHeaders;
|
||||
|
||||
// allows preflight requests
|
||||
if (AContext.Request.HTTPMethod = httpOPTIONS) then
|
||||
//normal request, no preflight request
|
||||
HandleRequest(AContext, AHandled);
|
||||
end
|
||||
else
|
||||
begin
|
||||
AContext.Response.StatusCode := HTTP_STATUS.OK;
|
||||
AHandled := True;
|
||||
//preflight
|
||||
HandlePreflightRequest(AContext, AHandled);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user