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
