How can I do HTTP GET and POST in Progress / OpenEdge ABL?

Progress docs spill a lot of ink on SOAP, but it's hard for me to find an example for a simple HTTP GET / POST with Progress ABL.

How can I set GET and POST lines to / from URLs?

Could the URL be https: //?

Can Progress skip HTTP Basic or HTTP Digest authentication?

+4
source share
4 answers

Openedge has built-in operators for processing SOAP services, but without a simple instruction for GET / POST. However, it does have a read / write mechanism to certain sockets. So you can use this to create an HTTP post routine or, for that matter, routines to handle any other socket based protocol.

There is a routine - http.p - that will do the GET for you. Lets you see how socket programming works, if nothing else. You should be able to easily modify it to perform a simple POST, but using SSL or obtaining authentication can take a lot of work. In this case, it might be easier for you to just exit CURL.

http.p was used to be available from freeframework.org, but I just checked and this domain has expired, so I posted the code below.

/*-----------------------------------------------------------------------* File........: http.p Version.....: 1.1 Description : Makes a "Get" request from an HTTP server Input Param : pHost = host name (without the "http://") pPort = port number (usually 80) pURL = begin with the first slash after the domain name. Output Param: pResult = 0 or 1 (character) pResponse = http headers returned pContent = the document returned. Author......: SE Southwell, Mario Paranhos - United Systems, Inc. (770) 449-9696 Created.....: 12/13/2000 Notes.......: Will not work with HTTPS. Usage: define var v-result as char no-undo. define var v-response as char no-undo. define var v-content as char no-undo. {&out} "Hello" skip. put stream webstream control null(0). run proc/http.p("www.whosplayin.com","80","/",output v-result,output v-response,output v-content). {&out} v-result "<hr>" skip html-encode(v-response) "<hr>" skip html-encode(v-content) "<hr>" skip . Last Modified: 10/20/01 - SES - Fixed to work in batch mode, or within a UDF. --------------------------------------------------------------------------*/ &SCOPED-DEFINE HTTP-NEWLINE CHR(13) + CHR(10) &SCOPED-DEFINE RESPONSE-TIMEOUT 45 DEFINE INPUT PARAMETER pHOST AS CHAR NO-UNDO. DEFINE INPUT PARAMETER pPORT AS CHAR NO-UNDO. DEFINE INPUT PARAMETER pURL AS CHAR NO-UNDO. DEFINE OUTPUT PARAMETER pRESULT AS CHAR NO-UNDO. DEFINE OUTPUT PARAMETER pRESPONSE AS CHAR NO-UNDO. DEFINE OUTPUT PARAMETER pContent AS CHAR NO-UNDO. DEFINE VARIABLE requestString AS CHAR NO-UNDO. DEFINE VARIABLE vSocket AS HANDLE NO-UNDO. DEFINE VARIABLE vBuffer AS MEMPTR NO-UNDO. DEFINE VARIABLE vloop AS LOGICAL NO-UNDO. DEFINE VARIABLE vPackets AS INTEGER NO-UNDO. DEFINE VARIABLE wStatus AS LOGICAL NO-UNDO. ASSIGN requestString = "GET " + pURL + " HTTP/1.0" + {&HTTP-NEWLINE} + "Accept: */*" + {&HTTP-NEWLINE} + "Host: " + phost + {&HTTP-NEWLINE} + /*"Connection: Keep-Alive" + {&HTTP-NEWLINE} + */ {&HTTP-NEWLINE}. /*OPEN THE SOCKET*/ CREATE SOCKET vSocket. vSocket:SET-READ-RESPONSE-PROCEDURE ("readHandler",THIS-PROCEDURE). ASSIGN wstatus = vSocket:CONNECT("-H " + phost + " -S " + pport) NO-ERROR. /*Now make sure the socket is open*/ IF wstatus = NO THEN DO: pResult = "0:No Socket". DELETE OBJECT vSocket. RETURN. END. /*Got socket - Now make HTTP request*/ SET-SIZE(vBuffer) = LENGTH(requestString) + 1. PUT-STRING(vBuffer,1) = requestString. vSocket:WRITE(vBuffer, 1, LENGTH(requestString)). SET-SIZE(vBuffer) = 0. /*Wait for a response*/ ASSIGN vloop = TRUE. /*Turns off automatically when request is done*/ DEFINE VAR vstarttime AS INTEGER. ASSIGN vstarttime = etime. WAITLOOP: DO WHILE vloop: PROCESS EVENTS. PAUSE 1. /* Build in timer in case sending is never set to NO this will terminate the program after 60 seconds start-Etime will be reset by WriteData each time there is activity on the socket to allow for long transmissions */ IF vstarttime + ({&RESPONSE-TIMEOUT} * 1000) < ETIME THEN DO: MESSAGE "timed out at " + string(etime - vstarttime) + " msec". vSocket:DISCONNECT(). ASSIGN pResult = "0:Failure". RETURN. END. /*No Response, or timed out*/ END. /*At this point, pResponse should be populated with the result (up to 32K)*/ vSocket:DISCONNECT(). DELETE OBJECT vSocket. /*All Done!*/ ASSIGN pResult = "1:Success". ASSIGN pContent = SUBSTRING(pResponse,INDEX(pResponse,{&HTTP-NEWLINE} + {&HTTP-NEWLINE}),-1) . ASSIGN pResponse = SUBSTRING(pResponse,1,INDEX(pResponse,{&HTTP-NEWLINE} + {&HTTP-NEWLINE})) . RETURN. /*Handle the response from the webserver*/ PROCEDURE readHandler: DEFINE VARIABLE bytesAvail AS INTEGER NO-UNDO. DEFINE VARIABLE b AS MEMPTR NO-UNDO. DEFINE VARIABLE lastBytes AS INTEGER NO-UNDO. IF vSocket:connected() THEN ASSIGN bytesAvail = vSocket:GET-BYTES-AVAILABLE(). IF bytesAvail = 0 THEN DO: /*All Done*/ ASSIGN vloop = FALSE. RETURN. END. /*OK, there something on the wire... Read it in*/ SET-SIZE(b) = bytesAvail + 1. vSocket:READ(b, 1, bytesAvail, 1). ASSIGN pResponse = pResponse + GET-STRING(b,1). SET-SIZE(b) = 0. END PROCEDURE. /*readHandler*/ 
+9
source

For future viewers to this question:

Openedge now (since 11.5.1, I believe) has built support for calling REST-based web services. They are enclosed in the provided .pl archive, which by default is not included in your PROPATH, therefore it must be processed first (or the archive can be moved to the "best place").

Propat can be installed in several ways, initialize files, registry, programmatically, etc. This can be done in ABL (if this is done so, it should be repeated for each new session).

 PROPATH = PROPATH + ",c:\pathtoprogress\OpenEdge\gui\OpenEdge.Net.pl". 

There is also a version in the tty directory, as well as an archive containing the source code in the src directory.

Here is a very simple example:

 USING OpenEdge.Net.HTTP.IHttpRequest. USING OpenEdge.Net.HTTP.IHttpResponse. USING OpenEdge.Net.HTTP.ClientBuilder. USING OpenEdge.Net.HTTP.RequestBuilder. DEFINE VARIABLE oRequest AS IHttpRequest NO-UNDO. DEFINE VARIABLE oResponse AS IHttpResponse NO-UNDO. oRequest = RequestBuilder:Get('http://stackoverflow.com/'):Request. oResponse = ClientBuilder:Build():Client:Execute(oRequest). MESSAGE oResponse:StatusCode SKIP oResponse:StatusReason SKIP VIEW-AS ALERT-BOX. 

The documentation for 11.6 can be found here.

+4
source

Progress Kbase ID: 20011: โ€œSample code for accessing a website via HTTP with 4GL socketsโ€ is also a good, typical example.

+2
source

I recommend using the Gordon Roberertson sample code above because there is a โ€œWAIT-FORโ€ article in Progress KB replaced with a loop. Thus, prcoedure ends after a timeout if something goes wrong.

Please note that changing anything in requestString can lead to timeouts. But adding a User-Agent is possible if you need to register on your web server:

 ASSIGN requestString = "GET " + Path + " HTTP/1.0" + {&HTTP-NEWLINE} + "Accept: */*" + {&HTTP-NEWLINE} + "User-Agent: " + "User Agent String" + {&HTTP-NEWLINE} + "Host: " + Host + {&HTTP-NEWLINE} + {&HTTP-NEWLINE}. 

Thanks to Gordon for his sample code.

0
source

All Articles