How to get the HTTP response from cURL?

jdpjamesp

ProgressTalk.com Moderator
Staff member
Still stuck on 11.7 on RHEL 8. Yes. I know. Sorry Tom. Migration to PASOE Webspeed is an absolute pain.

One of the side issues with 11.7 seems to be the flakiness of HTTP requests using the shipped classes. It works fine 95% of the time but then it gets a broken pipe. I've spoken in the past with Progress and the solution is to move to 12.2/8. In the meantime I'm having to change a bunch of REST interfaces to use cURL instead, but they don't want any of the functionality lost that was easy with HTTP requests.

I know that using -w I can get the HTTP Response code out on the command line, but I just can't work out how to capture that in my code. I need to get the payload into a file so I can parse it, but I also need to check the response code so I can handle the errors.

Code:
            cFileName = RESTHelper:GetTempOutfile ().
            cCurlCommand = SUBSTITUTE ("curl -X -sS --location --request GET &1 --header 'Content-Type: application/json' --header 'Authorization: Bearer &2' -o &3  -w '%~{http_code}'",
                                       icURI,
                                       icAuthentication,
                                       cFileName).
            
            INPUT STREAM sCurl THROUGH VALUE(cCurlCommand) NO-ECHO.
            REPEAT:
                ASSIGN cResult="".
                IMPORT STREAM sCurl UNFORMATTED cResult.
            END.
            INPUT STREAM sCurl CLOSE.

message "cCurlCommand: " cCurlCommand skip "cResult: " cResult view-as alert-box. 

            COPY-LOB FROM FILE cFileName TO cJsonOutput CONVERT TARGET CODEPAGE "UTF-8".

            oParser = NEW ObjectModelParser(). 

            oResponseObject = CAST (oParser:Parse(cJsonOutput),JsonObject) NO-ERROR.

            OS-DELETE VALUE (cFileName).

No matter what I do, cResult is blank. And I just can't work out how to get it to capture the http response code. When I run the cURL command on the command line I get the response output.
 
I've solved it.
Code:
            cCurlCommand = SUBSTITUTE ("curl -X -sS --location --request GET &1 --header 'Content-Type: application/json' --header 'Authorization: Bearer &2' 2>/dev/null -o &3 -w '%~{http_code}' > &4",
                                       icURI,
                                       icAuthentication,
                                       cFileName,
                                       cResponseFile).

Then get the http status from the cResponseFile.
 
I've spoken in the past with Progress and the solution is to move to 12.2/8.

Did they indicate what the problem was? Is it in the ABL code or the AVM?

If you can avoid shelling out from PASOE you should try to do so. It can become expensive due to the process sizes of the agents.
 
Yeah I know all about shelling out on PAS. Unfortunately we have about 1 million OS-COMMANDS all over the codebase. :( There's just no scope for fixing them. I'm fixing this particular nut by making it soft-settable between cURL and HTTP, so we can swap back once we get to 12.8 later this year.

I don't recall what the problem was but it was something to do with sockets.
 
Hi, I know that you have soled your issue, but I thought I would share my solution. This is just a fragment of the code but, hopefully it will give you some incite.

Code:
 AuthorizationHeader = SUBSTITUTE('Authorization: &1 &2':U,
                                     Classes.OAuth.OAuthAccessToken:AccessTokenType,
                                     Classes.OAuth.OAuthAccessToken:AccessToken).

ContentTypeHeader = 'Content-Type: application/soap+xml; charset=UTF-8':U.

osCommand = SUBSTITUTE('curl --trace-ascii "&9" --header "&1" -X POST --silent --show-error --header "&2" --data-binary "@&4" --stderr "&5" --dump-header "&6" --output "&7" --url "&3" --user-agent "Bad Ass Software"':U,
                           AuthorizationHeader ,
                           ContentTypeHeader,
                           SOAPEndPointURL,
                           SOAPPayloadFilename,
                           errorFilename,
                           headerFilename,
                           bodyFilename,
                           verboseFilename,
                           traceFilename).

   /* /** Execute the cURL command. **/   */
    OS-COMMAND SILENT VALUE(osCommand).

    FILE-INFO:FILE-NAME = errorFilename.

    /** If there was an error executing the curl command,
        no error file would of been created. **/
    IF FILE-INFO:FULL-PATHNAME EQ ? THEN
    DO:
        AppError = NEW Progress.Lang.AppError().
        AppError:ReturnValue = "cURL Error".
        AppError:AddMessage("Unable to Execute the cURL Command", 2000).
        RETURN ERROR AppError.
    END.

    /** If there was a cURL error, the information will be written
        to the error file create by the cURL command**/
    /** cURL ALWAYS creates a ERROR file but it's size would be
        ZERO if there was no errors**/

    IF FILE-INFO:FILE-SIZE GT 0 THEN
    DO:
        DEFINE VARIABLE CurlErrorResponce AS CHARACTER   NO-UNDO.

        INPUT FROM  VALUE(errorFilename) NO-ECHO .
            IMPORT UNFORMATTED CurlErrorResponce.
        INPUT CLOSE.

        AppError = NEW Progress.Lang.AppError().
        AppError:ReturnValue = "CURL Error":U.
        AppError:AddMessage( CurlErrorResponce , 2001).
        AppError:AddMessage( SOAPEndPointURL , 2001).
        RETURN ERROR AppError.
    END.

    /*** Do you suff here! ***/
 
Back
Top