views:

533

answers:

2

The Progress docs spill plenty of ink on SOAP, but I'm having trouble finding the example for a simple HTTP GET/POST with Progress ABL.

How do I GET and POST strings to/from a URL?

Can the URL be https://?

Can Progress provide HTTP Basic or HTTP Digest authentication?

+2  A: 

Openedge has built in statements for handling SOAP services, but no simple statement for a GET/POST. What it does have, however, is a mechanism to read / write to specific sockets. So you could use this to build a HTTP post routine, or for that matter a routine to handle any other socket based protocol.

There is a routine - http.p - which will do a GET for you. Will let you see how the socket programming works if nothing else. You should be able to modify it quite easily to do a simple POST, but using SSL or getting into authentication might take quite a bit of work. You might be easier just dropping out to CURL in this case.

http.p used to be available from freeframework.org, but I've just checked and that domain has expired, so I've 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......: S.E. 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's 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*/
Gordon Robertson
+1  A: 

Progress Kbase ID: 20011: "Sample Code To Access a Web Site via HTTP with 4GL Sockets" is also a nice, generic example.

Tom Bascom