196 lines
11 KiB
Plaintext
196 lines
11 KiB
Plaintext
Function HTTP_MCP(Request, ProcErr)
|
|
/***********************************************************************************************************************
|
|
|
|
This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written
|
|
permission from SRP Computer Solutions, Inc.
|
|
|
|
Name : HTTP_MCP (HTTP Master Controller Program)
|
|
|
|
Description : HTTP Controller program for the application.
|
|
|
|
Notes : In an MVC framework this is the 'Controller' routine that accepts HTTP requests nad routes them to
|
|
the core Master Controller Program (MCP). HTTP_MCP is written as a replacement to the
|
|
RUN_OECGI_REQUEST listner. It is intended to be a cleaner listener designed to allow REST style
|
|
API calls and better control over request and response handling. Since it is a listner, it should
|
|
be only modified when core functionality needs to be added or modified. Application specific
|
|
changes should be kept within one or more of the called services.
|
|
|
|
Parameters :
|
|
Request [in] -- The request array which includes the HTTP request and OECGI provided information.
|
|
ProcErr [in] -- Contains error messages in the event of a prior crash (such as a runtime error). The
|
|
specified listener is automatically called in these situations with the ProcErr argument
|
|
populated. Therefore, a check for data in this argument needs to occur immediately so that
|
|
the error can be properly managed and returned to the caller in a suitable format. For
|
|
RUN_OECGI_REQUEST applications, INET_ABORTED would normally be called to handle this.
|
|
Response [out] -- HTTP response to send back to the OECGI.
|
|
|
|
History : (Date, Initials, Notes)
|
|
02/06/15 dmb [SRPFW-90] Original programmer. Copied from INET_MCP but refactored for REST API requests.
|
|
04/14/15 dmb [SRPFW-90] Add missing '\' in the path for debug files to be written to.
|
|
02/23/16 dmb [SRPFW-103] Move the request/response capture path defintion into the
|
|
SYSENV\SRP_HTTP_FRAMEWORK_SETUP record.
|
|
02/25/16 dmb [SRPFW-108] Replace Xlate with GetCapturePath service.
|
|
03/09/16 dmb [SRPFW-111] Call GetEntryPointService before calling RunHTTPService.
|
|
03/09/16 dmb [SRPFW-112] Remove HTTP_SERVICE_SETUP insert.
|
|
03/09/16 dmb [SRPFW-112] Call GetHTTPPathInfo before calling RunHTTPService.
|
|
05/17/16 dmb [SRPFW-125] Add support for ProcErr. Create a generic error response.
|
|
10/01/16 dmb [SRPFW-128] Add code to track API execution time using SRP_Stopwatch. Display the time in
|
|
the Response log that is written into the debug folder.
|
|
02/18/17 dmb [SRPFW-151] Report the decoded Authorization data in the Response log.
|
|
02/27/17 dmb [SRPFW-125] Add support for the GetProcErrService service. If missing, the default ProcErr
|
|
process logic will continue to work.
|
|
03/03/17 dmb [SRPFW-154] Replace direct logging with the CreateLogFile service.
|
|
03/08/17 dmb [SRPFW-155] Add support for setting the debugger mode and intercept.
|
|
07/01/17 dmb [SRPFW-184] Refactor using Enhanced BASIC+ syntax.
|
|
11/01/18 dmb [SRPFW-256] Add support for the GetServerEnabled service. Set status to 503 is server is not
|
|
enabled.
|
|
11/18/18 dmb [SRPFW-257] Add support for the GetAPICallProcedure service. Use the RunWebAPI or
|
|
RunHTTPService service as appropriate.
|
|
12/12/18 dmb [SRPFW-257] If Get_Status returns an error, produce a GetStatus log and then use the
|
|
SetResponseError service so the client gets a detailed response.
|
|
12/16/19 dmb [SRPFW-296] Update code that calls the CreateLogFile service for Get_Status conditions so
|
|
that the status detail is better formatted. Also, clear the error condition to prevent
|
|
the OECGI from making a ProcErr call.
|
|
|
|
***********************************************************************************************************************/
|
|
|
|
#pragma precomp SRP_PreCompiler
|
|
|
|
$insert LOGICAL
|
|
$insert HTTP_INSERTS
|
|
$insert INET_EQUATES
|
|
$insert INET_HEADERS
|
|
$insert Msg_Equates
|
|
|
|
Equ CRLF$ to \0D0A\
|
|
|
|
Declare subroutine SRP_Stopwatch, Set_Status, RTI_Set_Debugger
|
|
Declare function SRP_Stopwatch, RTI_OS_Directory
|
|
|
|
If Assigned(Request) else Request = ''
|
|
If Assigned(ProcErr) else ProcErr = ''
|
|
If ProcErr NE '' then
|
|
// Runtime errors produce two copies of the error description in the ProcErr argument. Just divide in half to get
|
|
// one copy.
|
|
If ProcErr[1, Len(ProcErr) / 2] EQ ProcErr[Len(ProcErr) / 2 + 1, Len(ProcErr) / 2] then
|
|
ProcErr = ProcErr[1, Len(ProcErr) / 2]
|
|
end
|
|
end
|
|
|
|
// Start timing the overall API.
|
|
SRP_Stopwatch('Reset')
|
|
SRP_Stopwatch('Start', 'WebAPI')
|
|
|
|
// Set the mode for the debugger and identify the debugger intercept service if applicable.
|
|
DebuggerSetting = HTTP_Services('GetDebuggerSetting')
|
|
If DebuggerSetting EQ 2 then
|
|
DebuggerService = HTTP_Services('GetDebuggerService')
|
|
end else
|
|
DebuggerService = ''
|
|
end
|
|
RTI_Set_Debugger(DebuggerSetting, DebuggerService)
|
|
|
|
// Use HTTP_Services to store the HTTP request as provided by the OECGI and also to retreive the relevant request
|
|
// information that will be used below.
|
|
HTTP_Services('SetSessionID')
|
|
HTTP_Services('SetOECGIRequest', Request)
|
|
HTTP_Services('SetOECGIProcErr', ProcErr)
|
|
HTTP_Services('SetRequestHeaderFields')
|
|
HTTP_Services('SetQueryFields')
|
|
|
|
// Create the HTTP Request log file.
|
|
HTTP_Services('CreateLogFile', 'Request')
|
|
|
|
If ProcErr NE '' then
|
|
// An unexpected error occurred with the most recent request. The nature of the error (usually a runtime error) will
|
|
// be contained in the ProcErr argument. Generate a response so the caller will receive a well formatted reply.
|
|
AbortedService = HTTP_Services('GetAbortedService')
|
|
|
|
If AbortedService NE '' then
|
|
// There is a procedural error service designated to handle this condition. Allow it to process the error and
|
|
// generate the response.
|
|
Call @AbortedService(ProcErr)
|
|
end else
|
|
// There is no procedural error service so process this using default logic.
|
|
Swap \00\ with \0D0A\ in ProcErr
|
|
Swap @FM with \0D0A\ in ProcErr
|
|
Swap @VM with \0D0A\ in ProcErr
|
|
Swap @SVM with \0D0A\ in ProcErr
|
|
|
|
// The ProcErr always contains two copies of the error description so just divide in half to get one copy.
|
|
If ProcErr[1, Len(ProcErr) / 2] EQ ProcErr[Len(ProcErr) / 2 + 1, Len(ProcErr) / 2] then
|
|
ProcErr = ProcErr[1, Len(ProcErr) / 2]
|
|
end
|
|
|
|
HTTP_Services('SetResponseError', '', '', 500, ProcErr, FullEndpointURL)
|
|
end
|
|
end else
|
|
ServerEnabled = HTTP_Services('GetServerEnabled')
|
|
// Check to see if the server is still enabled.
|
|
If ServerEnabled then
|
|
// Authenticate the request using HTTP Authentication Services. If the user is not validated then the appropriate
|
|
// response status and headers will be set. If no authentication is required then the AuthenticateRequest service
|
|
// should set the UserAuthenticated response to True as a default.
|
|
//
|
|
// This service is also where global response headers are set, regardless of whether the user is authenticated.
|
|
//
|
|
// Note: Even if authentication is disabled via the SRP_HTTP_FRAMEWORK_SETUP configuration record, the
|
|
// AuthenticateRequest should still be called. It will inspect the flag and set the response accordingly.
|
|
UserAuthenticated = HTTP_Authentication_Services('AuthenticateRequest')
|
|
|
|
If UserAuthenticated then
|
|
// Call the API based on the type of calling procedure specified in the setup.
|
|
APICallProcedure = HTTP_Services('GetAPICallProcedure')
|
|
If APICallProcedure EQ 'Web API' then
|
|
HTTP_Services('RunWebAPI')
|
|
end else
|
|
EntryPointService = HTTP_Services('GetEntryPointService')
|
|
RemainingURL = HTTP_Services('GetHTTPPathInfo')
|
|
HTTP_Services('RunHTTPService', EntryPointService, RemainingURL)
|
|
end
|
|
end
|
|
end else
|
|
HTTP_Services('SetResponseError', '', '', 503, 'Server is temporarily disabled.')
|
|
end
|
|
end
|
|
|
|
// Get the full response to send back to the requesting client.
|
|
Response = HTTP_Services('GetResponse')
|
|
|
|
// Stop timing the overall API.
|
|
SRP_Stopwatch('Stop', 'WebAPI')
|
|
TimeToExecute = SRP_Stopwatch('GetBenchmark', 'WebAPI')
|
|
|
|
// Check the status before logging and returning the HTTP Response. If there is a status error then the Response
|
|
// variable should be cleared and no log generated. The OEngineServer will resubmit a request with the error detail
|
|
// the the ProcErr service will handle and log this.
|
|
If Get_Status() EQ 0 then
|
|
HTTP_Services('CreateLogFile', 'Response', Response)
|
|
end else
|
|
StatusCode = ''
|
|
Status = Get_Status(StatusCode)
|
|
HTTP_Services('SetResponseError', '', '', 500, 'Get_Status Error', FullEndpointURL, 'Status' : @FM : 'StatusCode', Status : @FM : StatusCode<1, 1> : ' - ' : StatusCode<1, 2>)
|
|
Response = HTTP_Services('GetResponse')
|
|
HTTP_Services('CreateLogFile', 'GetStatus', Response)
|
|
Set_Status(0)
|
|
end
|
|
|
|
// Engage the debugger if requested.
|
|
If HTTP_Services('GetRequestHeaderField', 'Debug') then Debug
|
|
|
|
// Clear all saved values that were set in this session to avoid subsequent requests to a running engine from getting
|
|
// invalid data.
|
|
HTTP_Services('ClearSettings')
|
|
|
|
// Clean up processes, as needed, that were set in this session to avoid subsequent requests to a running engine from
|
|
// getting invalid data.
|
|
HTTP_Authentication_Services('CleanUp')
|
|
|
|
// Clear any possible internal OpenInsight errors so everything will process normally. Note, traditional INET does not
|
|
// clear this flag automatically. This is how INET_ABORTED gets called if there is an SSP error. The SRP HTTP Framework
|
|
// clears this flag by default because the developer can still trap Get_Status() in the relevant web service code and
|
|
// create a custom HTTP response. Thus, the ProcErr service will only be called if there is a runtime error condition.
|
|
* Set_Status(0)
|
|
|
|
Return Response
|